1前沿
使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间
1.1ribbon配置
ribbon:
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,默认false
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 2000 #ribbon请求连接的超时时间,默认值2000
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
1.2 hystrix熔断配置
hystrix:
command:
default: #default全局有效,service id指定应用有效
execution:
timeout:
#是否开启超时熔断
enabled: true
isolation:
thread:
timeoutInMilliseconds: 4000 #断路器超时时间,默认1000ms
feign:
hystrix:
enabled: true
2测试各个配置的效果
开了一个Eureka服务中心
开了两个个服务eureka-client,端口分别为8762
和8763
,进行负载均衡
eureka-client的方法:
package com.example.cloud_client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
/**
* @author 庄勇
* @date 2018/12/11 16:27
*/
@RestController
public class TestController {
@Value("${server.port}")
String port;
@Value("${spring.application.name}")
String serviceName;
@RequestMapping(value="/test", method = RequestMethod.GET)
public String index(@RequestParam("millis") int millis) throws InterruptedException {
System.out.println("8762---"+System.currentTimeMillis());
Thread.sleep(millis);
return "serviceName=" + serviceName + "-------port=" + port;
}
}
feignClient
eureka-feign调用client的方法,通过传参数millis
来控制client线程休眠的时间
controller
package com.example.eurekafeignclient;
import com.example.eurekafeignclient.inter.FeignInterface;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 庄勇
* @date 2018/12/12 9:37
*/
@RestController
public class FeiConsumerController {
@Autowired
FeignInterface feignInterface;
@RequestMapping("eureka-client")
public String feignConsumer(@RequestParam int millis) {
long start = System.currentTimeMillis();
System.out.println(start);
String a = feignInterface.IndexInfo(millis);
long end = System.currentTimeMillis();
System.out.println(end);
System.out.println("调用eureka-client服务时长" + (end-start) + "ms");
return a;
}
}
serveice
package com.example.eurekafeignclient.inter;
import com.example.eurekafeignclient.HelloServiceFallback;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author 庄勇
* @date 2018/12/12 9:35
*/
@FeignClient(value="eureka-client",fallback = HelloServiceFallback.class)
public interface FeignInterface {
@RequestMapping(value="/test", method = RequestMethod.GET)
String IndexInfo(@RequestParam(value="millis") int millis);
}
熔断方法fallback
package com.example.eurekafeignclient;
import com.example.eurekafeignclient.inter.FeignInterface;
import org.springframework.stereotype.Component;
/**
* @author 庄勇
* @date 2018/12/12 10:27
*/
@Component
public class HelloServiceFallback implements FeignInterface {
@Override
public String IndexInfo(int millis) {
System.out.println("熔断");
return "熔断";
}
}
主要测试几种情况
1, ribbon的超时时间和Hystrix的超时时间的关系
2,ribbon的超时时间和Hystrix的超时时间的什么时候生效
3,重试时候参数配置
4,其他
测试1(无重试)
无重试1
(ReadTimeout和timeoutInMilliseconds关系)
全局参数:ribbon和hystrix参数设置没有重试
OkToRetryOnAllOperations: false
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 5000 #断路器超时时间,默认1000ms
条件1:Port=8762 Millis=1000ms Port=8763 Millis=1000ms
结果: 打印port=8762----------调用eureka-client服务时长1013ms
打印port=8763----------调用eureka-client服务时长1011ms
条件2:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
熔断1544750879175调用eureka-client服务时长3003ms
熔断 1544750757822 调用eureka-client服务时长3003ms
条件3:Port=8762 Millis=5500ms Port=8763 Millis=5500ms
熔断1544750879175调用eureka-client服务时长3005ms
熔断1544750879175调用eureka-client服务时长3007ms
无重试2
以下修改了参数ReadTimeout和timeoutInMilliseconds进行测试
OkToRetryOnAllOperations: false
MaxAutoRetries: 0 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
ReadTimeout: 5000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 3000 #断路器超时时间,默认1000ms
条件4:Port=8762 Millis=5500ms Port=8763 Millis=5500ms
熔断1544750879175调用eureka-client服务时长3364ms
熔断1544750879175调用eureka-client服务时长3005ms
条件5:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
熔断1544750879175调用eureka-client服务时长3004ms
熔断1544750879175调用eureka-client服务时长3003ms
条件6:Port=8762 Millis=1000ms Port=8763 Millis=1000ms
调用eureka-client服务时长1010ms
调用eureka-client服务时长1003ms
停掉8762和8763服务
条件7:Port=8762 Millis=1000ms Port=8763 Millis=1000ms
打印----------熔断1544754831161调用eureka-client服务时长1007ms
条件8:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
打印----------熔断1544754945541调用eureka-client服务时长1007ms
条件9:Port=8762 Millis=5500ms Port=8763 Millis=5500ms
打印----------熔断1544755009533调用eureka-client服务时长1006ms
结论:
无重试的时候,超时时间与ReadTimeout和timeoutInMilliseconds最小值相关,此时谁的值小谁生效
停掉服务时,客户服务停止时,超时时间采用的是timeoutInMilliseconds的默认时间1000ms???
测试2(有重试)
OkToRetryOnAllOperations: false
MaxAutoRetries: 1 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 5000 #断路器超时时间,默认1000ms
重试次数=(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries) 测试中可验证
条件10:Port=8762 Millis=1000ms Port=8763 Millis=1000ms
打印----------1544756976651调用eureka-client服务时长1955ms
条件11:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
打印8762----------熔断1544757079644调用eureka-client服务时长5017ms
打印8763----------熔断1544757189984调用eureka-client服务时长5004ms
此时出现了重试 修改参数
OkToRetryOnAllOperations: false
MaxAutoRetries: 1 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 0 #对切换实例的重试次数,默认1
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 10000 #断路器超时时间,默认1000ms
条件12:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
打印8762----------熔断1544757421610调用eureka-client服务时长6009ms
打印8762----------熔断1544757542162调用eureka-client服务时长6009ms
打印8762----------熔断1544757546794调用eureka-client服务时长6010ms
此时修改参数MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
OkToRetryOnAllOperations: false
MaxAutoRetries: 1 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 10000 #断路器超时时间,默认1000ms
条件13:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
结果:打印
熔断1544757776401调用eureka-client服务时长12098ms
熔断1544757776401调用eureka-client服务时长12552ms
熔断1544757776401调用eureka-client服务时长12707ms
熔断1544757776401调用eureka-client服务时长12403ms
熔断1544757776401调用eureka-client服务时长12763ms
熔断1544757776466调用eureka-client服务时长12008ms
OkToRetryOnAllOperations: false
MaxAutoRetries: 1 #对当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 #对切换实例的重试次数,默认1
ReadTimeout: 3000 #负载均衡超时时间,默认值5000
ConnectTimeout: 1000 #ribbon请求连接的超时时间,默认值2000
timeoutInMilliseconds: 5000 #断路器超时时间,默认1000ms
条件13:Port=8762 Millis=3500ms Port=8763 Millis=3500ms
结果:打印
熔断1544759011132调用eureka-client服务时长5003ms
于此同时 8762服务器打印了
8763服务器打印了
说明重试并没有结束
结论:
重试次数=(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)
重试时间=(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)*ReadTimeout+网络响应时间
并且由于重试应为执行熔断后而停止重试,从而造成不必要的情况发生,因此熔断时间应该在重试时间之后,
(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)*ReadTimeout+网络响应时间+ReadTimeout<timeoutInMilliseconds