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,端口分别为87628763,进行负载均衡

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

spring openfeign 超时时间配置 feign调用超时时间_python

 打印port=8763----------调用eureka-client服务时长1011ms

spring openfeign 超时时间配置 feign调用超时时间_java_02

条件2:Port=8762  Millis=3500ms   Port=8763  Millis=3500ms  

熔断1544750879175调用eureka-client服务时长3003ms

熔断 1544750757822 调用eureka-client服务时长3003ms

spring openfeign 超时时间配置 feign调用超时时间_spring_03

条件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

spring openfeign 超时时间配置 feign调用超时时间_spring_04

条件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服务器打印了

spring openfeign 超时时间配置 feign调用超时时间_System_05

8763服务器打印了

spring openfeign 超时时间配置 feign调用超时时间_java_06

说明重试并没有结束



结论:

重试次数=(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)

重试时间=(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)*ReadTimeout+网络响应时间

并且由于重试应为执行熔断后而停止重试,从而造成不必要的情况发生,因此熔断时间应该在重试时间之后,

(MaxAutoRetries+MaxAutoRetriesNextServer+MaxAutoRetriesNextServer*MaxAutoRetries)*ReadTimeout+网络响应时间+ReadTimeout<timeoutInMilliseconds