目录
一、SpringCloud超时配置参数
1.1 ribbon配置参数
# ribbon配置
ribbon:
OkToRetryOnAllOperations: false # 所有请求重试,默认false
ReadTimeout: 3000 # 负载均衡超时时间,默认值5000ms
ConnectTimeout: 1000 # 请求连接的超时时间,默认值2000ms
MaxAutoRetries: 0 # 当前实例的重试次数,默认0
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1
1.2 hystrix配置参数
# hystrix开启
feign:
hystrix:
enabled: true
hystrix:
command:
default: # default全局有效,service id指定应用有效
execution:
timeout:
# true则超时根据熔断超时,false则ribbon控制
enabled: true
isolation:
thread:
timeoutInMilliseconds: 1500 # 断路器超时时间,默认1000ms
1.3 测试代码
这里有两个服务instance-demo、instance-test,instance-demo通过feign调用instance-test,以下是两个服务的相关代码。
a. instance-demo
package com.common.instance.demo.controller;
import com.common.instance.demo.core.Response;
import com.common.instance.demo.feign.FeignMongoDbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @description Hystrix测试
* @author TCM
* @version 1.0
* @date 2021/3/23 22:21
**/
@RestController
@RequestMapping("/feign/hystrix")
@Api(tags = "Hystrix测试")
public class FeignHystrixController {
@Resource
private FeignMongoDbService feignMongoDbService;
@GetMapping("/timeOut")
@ApiOperation("Hystrix超时测试")
public Response<String> timeOut(int mills) {
return feignMongoDbService.timeOut(mills);
}
}
package com.common.instance.demo.feign;
import com.common.instance.demo.core.Response;
import com.common.instance.demo.entity.OverScreenJob;
import com.common.instance.demo.feign.fallback.HystrixServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* @description feign调用mongodb
* @author tcm
* @version 1.0.0
* @date 2021/1/15 16:49
**/
@FeignClient(name = "instance-test", fallback = HystrixServiceFallBack.class)
public interface FeignMongoDbService {
@PostMapping(value = "instance-test/test/mongodb/listAll")
Response<List<OverScreenJob>> listAll();
@GetMapping(value = "instance-test/hystrix/timeOut")
Response<String> timeOut(@RequestParam(value = "mills") int mills);
}
package com.common.instance.demo.feign.fallback;
import com.common.instance.demo.core.Response;
import com.common.instance.demo.entity.OverScreenJob;
import com.common.instance.demo.feign.FeignMongoDbService;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @description 调用feign熔断
* @author TCM
* @version 1.0
* @date 2021/3/24 19:59
**/
@Component
public class HystrixServiceFallBack implements FeignMongoDbService {
@Override
public Response<List<OverScreenJob>> listAll() {
return null;
}
@Override
public Response<String> timeOut(int mills) {
return Response.success("进入熔断");
}
}
b instance-test
package com.common.instance.test.controller;
import com.common.instance.test.core.Response;
import com.log.util.LogUtil;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description Hystrix测试
* @author TCM
* @version 1.0
* @date 2021/3/23 22:01
**/
@RestController
@RequestMapping("/hystrix")
@Api(tags = "Hystrix测试")
public class HystrixController {
@Value("${spring.cloud.client.ip-address}")
private String ipAddress;
/**
* 测试超时重试机制
* @param mills 超时设置
* @return
*/
@GetMapping("/timeOut")
public Response<String> timeOut(int mills) {
LogUtil.info(String.format("client服务-%s [timeOut方法]收到请求,阻塞%sms", ipAddress, mills));
try {
Thread.sleep(mills);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Response.success(String.format("client服务-%s 请求ok!!!", ipAddress));
}
}
二、对比各个超时时间
本章节,根据配置参数,以表格的形式列出测试表格并分析。
2.1 测试数据
样例 | 配置参数 | 传值/ms | 结果 | 是否熔断 |
test1 | hystrix: command: default: # default全局有效,service id指定应用有效 execution: timeout: # true则超时根据熔断超时,false则ribbon控制 enabled: true isolation: thread: timeoutInMilliseconds: 5000 # 断路器超时时间,默认1000ms # ribbon配置 ribbon: OkToRetryOnAllOperations: false # 所有请求重试,默认false ReadTimeout: 1000 # 负载均衡超时时间,默认值5000ms ConnectTimeout: 3000 # 请求连接的超时时间,默认值2000ms MaxAutoRetries: 0 # 当前实例的重试次数,默认0 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1 | 900 | client服务-192.168.1.3 请求ok!!! | NO |
1200 | 进入熔断 | YES | ||
2000 | 进入熔断 | YES | ||
4000 | 进入熔断 | YES | ||
6000 | 进入熔断 | YES | ||
test2 | hystrix: command: default: # default全局有效,service id指定应用有效 execution: timeout: # true则超时根据熔断超时,false则ribbon控制 enabled: true isolation: thread: timeoutInMilliseconds: 900 # 断路器超时时间,默认1000ms # ribbon配置 ribbon: OkToRetryOnAllOperations: false # 所有请求重试,默认false ReadTimeout: 1000 # 负载均衡超时时间,默认值5000ms ConnectTimeout: 3000 # 请求连接的超时时间,默认值2000ms MaxAutoRetries: 0 # 当前实例的重试次数,默认0 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1 | 600 | client服务-192.168.1.3 请求ok!!! | NO |
800 | client服务-192.168.1.3 请求ok!!! | NO | ||
900 | 进入熔断 | YES | ||
1200 | 进入熔断 | YES | ||
2000 | 进入熔断 | YES | ||
test3 | hystrix: command: default: # default全局有效,service id指定应用有效 execution: timeout: # true则超时根据熔断超时,false则ribbon控制 enabled: true isolation: thread: timeoutInMilliseconds: 5000 # 断路器超时时间,默认1000ms # ribbon配置 ribbon: OkToRetryOnAllOperations: false # 所有请求重试,默认false ReadTimeout: 3000 # 负载均衡超时时间,默认值5000ms ConnectTimeout: 1000 # 请求连接的超时时间,默认值2000ms MaxAutoRetries: 0 # 当前实例的重试次数,默认0 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1 | 900 | client服务-192.168.1.3 请求ok!!! | NO |
1200 | client服务-192.168.1.4 请求ok!!! | NO | ||
2000 | client服务-192.168.1.5 请求ok!!! | NO | ||
4000 | 进入熔断 | YES | ||
6000 | 进入熔断 | YES | ||
test4 | hystrix: command: default: # default全局有效,service id指定应用有效 execution: timeout: # true则超时根据熔断超时,false则ribbon控制 enabled: true isolation: thread: timeoutInMilliseconds: 1500 # 断路器超时时间,默认1000ms # ribbon配置 ribbon: OkToRetryOnAllOperations: false # 所有请求重试,默认false ReadTimeout: 3000 # 负载均衡超时时间,默认值5000ms ConnectTimeout: 1000 # 请求连接的超时时间,默认值2000ms MaxAutoRetries: 0 # 当前实例的重试次数,默认0 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1 | 900 | client服务-192.168.1.3 请求ok!!! | NO |
1200 | client服务-192.168.1.4 请求ok!!! | NO | ||
1600 | 进入熔断 | YES | ||
2000 | 进入熔断 | YES | ||
4000 | 进入熔断 | YES | ||
test5 | hystrix: command: default: # default全局有效,service id指定应用有效 execution: timeout: # true则超时根据熔断超时,false则ribbon控制 enabled: false isolation: thread: timeoutInMilliseconds: 5000 # 断路器超时时间,默认1000ms # ribbon配置 ribbon: OkToRetryOnAllOperations: false # 所有请求重试,默认false ReadTimeout: 2500 # 负载均衡超时时间,默认值5000ms ConnectTimeout: 1000 # 请求连接的超时时间,默认值2000ms MaxAutoRetries: 0 # 当前实例的重试次数,默认0 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数,默认1 | 900 | client服务-192.168.1.3 请求ok!!! | NO |
1200 | client服务-192.168.1.4 请求ok!!! | NO | ||
2400 | client服务-192.168.1.5 请求ok!!! | NO | ||
2600 | 进入熔断 | YES | ||
4000 | 进入熔断 | YES |
2.2 测试分析
a.test1与test2对比:hystrix.command.default.execution.timeout.enabled=true时, timeoutInMilliseconds与ribbon.ReadTimeout起作用,谁值小谁其作用;
b.test1与test3对比:hystrix.command.default.execution.timeout.enabled=true时, ConnectTimeout不起作用;timeoutInMilliseconds与ribbon.ReadTimeout起作用,谁值小谁其作用;
c.test1与test5对比:hystrix.command.default.execution.timeout.enabled=false时,ConnectTimeout起作用,ReadTimeout > ConnectTimeout。
以上测试结果,是可以理解的。ribbon负责一个服务多个实例之间的切换,到达多实例负载均衡;而Hystrix是ribbon负载均衡后,确定的某一个实例来处理请求。从层级上说,先有ribbon后有hystrix。所以hystrix.command.default.execution.timeout.enabled=false(即Hystrix超时没有开启),这样ribbon超时配置就其作用了。与此同时,ReadTimeout > ConnectTimeout原因是可以切换实例重试。
hystrix.command.default.execution.timeout.enabled=true(即Hystrix超时开启),这样ribbon和hystrix共同起作用,但是谁的值小谁熔断。
三、Hystrix的作用
如上图所示,假如每秒有10000个请求订单服务,每个请求都要通过feign调用积分、仓储、库存服务。由于积分服务网络慢或宕机,这样所有请求都卡在积分服务,那么订单服务也就卡住了,这就是微服务中的服务雪崩问题。此时Hystrix作用就来了,因积分服务不能即时响应导致了超出配置的超时时间,这样feign调用就会发生熔断,返回对应的fallback处理,从而不影响接下来的流程,整个订单服务也不会因为积分服务的异常而卡住。
由上图可知,调用积分、仓储、库存服务的订单服务,都会为每个服务开一个线程池,独立处理各自的服务,还不影响其他服务的调用,进行服务的隔离作用。