SpringCloud Hystrix熔断器
# Hystrix 熔断器
Hystrix 是一个用于分布式系统的 ==延迟==、==容错== 的开源库。在分布式系统里,许多依赖不可避免的调用失败,比如超时、异常等。==Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败==,避免级联故障,以提高分布式系统的弹性。
Hystrix 能为系统做:
- 保护并控制通过第三方客户库访问的 延迟 和 故障(通常是通过网络访问的依赖关系)
- 停止复杂分布式系统中的级联故障
- 失败快速和快速恢复
- 回退,并尽可能优雅地降级
- 实现近实时监控、警报和操作控制
# 雪崩效应
在 分布式系统 中通常有多个服务进行调用,这一高并发的过程难免会有故障的时候,消费者一旦请求出现故障,请求会被堵塞,tomcat不会释放该线程,于是请求越来越多,最终导致服务器资源耗尽,形成了雪崩效应
提供者E 突然发生故障,导致线程堵塞
# 线程隔离&服务降级
线程隔离:将请求资源用 ==线程池== 进行隔离,如果线程池已满,将不进行排队,直接判定为失败
服务降级:请求失败,会返回失败的提示(如 :对不起,网络太拥堵了 请求服务降级有以下两种的情况
- 被分配到已满的线程池
- 请求超时(超时时长自行配置
# 示例
代码在上篇文章的基础上进行添加编辑:Java学习记录 03Spring Cloud 负载均衡Ribbon (opens new window)
消费者 添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
消费者 启动类 ,添加注解
@EnableCircuitBreaker
// @EnableDiscoveryClient // Eureka客户端 // @EnableCircuitBreaker // 熔断器 // @SpringBootApplication // 该注解组合以上3个注解 @SpringCloudApplication public class ConsumerApplication { // .... }
@SpringCloudApplication
注解整合了 Eureka、Hystrix、启动器 注解消费者 服务降级处理 ,controller
降级处理有两种方式:
方式 注解 用于 优点 1 @HystrixCommand(fallbackMethod = "{降级服务的方法名}")
方法 降级服务的方法可获取方法的参数 2 @DefaultProperties(defaultFallback = "{降级服务的方法名}")
类、接口、枚举、Annotation类型 可统一降级服务,降低维护成本 @RestController @RequestMapping("consumer") @Slf4j // 方式2.1 多接口响应 @DefaultProperties (defaultFallback = "defaultFallback") public class ConsumerController { @Autowired private RestTemplate restTemplate; //... @RequestMapping("{id}") // 方式1.1 单个接口响应 // @HystrixCommand(fallbackMethod = "queryByIdFallback") // 方式2.2 @HystrixCommand public String findById(@PathVariable Long id) throws InterruptedException { String url = "HTTP://user-service/user/"+id; return restTemplate.getForObject(url , String.class); } // 方式1.2(方式1有参数接收,因 方式1 写在方法里! public String queryByIdFallback(Long id) { log.error("查询信息失败1,id : {}",id); return "对不起,网络太拥堵了!(Test1"; } // 方式2.3 public String defaultFallback() { log.error("查询信息失败2"); return "对不起,网络太拥挤了!(Test2"; } }
修改了 findById()方法 的返回值,从 提供者 那获取也是json格式,为了也方便降级数据的返回,因此返回值为String
测试
- 依次打开 Eureka、server、consumer 三个服务
- 访问 http://localhost:8080/consumer/1 (返回 数据
- 关闭 server 再次访问以上请求
- 页面返回:"对不起,网络太拥挤了!(Test2 " (成功降级服务处理
# 超时设置
消费者
application.yml
,添加超时配置# 请求超过2s回返回错误,默认1s(测试用 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
提供者 controller 休眠 (只为触发超时 休眠写 被调用服务的方法里
@RequestMapping("{id}") public User findById(@PathVariable Long id) { /* 测试 : 超时请求延迟 识别判断:保留1为小数 */ Thread.sleep(2000); // Thread.sleep(1900); return service.findById(id); }
测试
- 依次打开 Eureka、server、consumer 三个服务
- 打开浏览器F12 检查请求的时长,访问 http://localhost:8080/consumer/1 (返回 数据
- 休眠2s返回结果:"对不起,网络太拥挤了!(Test2 " (成功降级服务处理
- 休眠1.9s返回结果:数据
# 熔断器
熔断器它会在一段时间内检测请求异常,如果末段时间内异常超出一定比例时,则迫使请求进行 降级服务 ,并非 调用提供者,从而防止更多请求发生同样的失败操作。一旦触发熔断器打开,需要等待休眠,休眠结束后会释放少部分请求进行测试,如果还是出现问题,则继续打开熔断器,否则关闭熔断器
日常例子:
好比家用的漏电开关,一旦电压不稳定,就打开电闸,断开电源
熔断器计算 出来的状态分别有:
- Closed (关闭):所有请求正常访问
- Open (打开):所有请求降级服务
- Half-Open (半打开):当打开的熔断器休眠结束后,会释放部分请求,如果都是健康,就关闭熔断器,否则保持打开熔断器
熔断器的 默认配置&触发条件:
- 最小请求次数 20次
- 异常比例阈值 50%
- 熔断休眠时长 5s
解释:5s内访问次数20次,如果超过10次的是异常,则打开熔断器 休眠5s
# 示例
在以上代码的基础上进行编辑
消费者 controller 制造异常 (上面的 Hystrix依赖 也要有!!!)
@RequestMapping("{id}") @HystrixCommand public String findById(@PathVariable Long id) throws InterruptedException { // 测试 :异常制造 (实现熔断器报错预期 if (id == 1) { throw new RuntimeException("忙碌"); } //.. String url = "HTTP://user-service/user/"+id; return restTemplate.getForObject(url , String.class); }
注意:上面测试代码,如果打开有休眠,先清空添加的休眠代码
测试 流程:先访问 ==请求1== 20+次 (制造异常触发熔断器),然后在访问 ==请求2== (访问失败)
- 触发阈值的请求:http://localhost:8080/consumer/1 (注定失败
- 测试熔断的请求:http://localhost:8080/consumer/2 (测试熔断
熔断器的触发条件上面说有,就不赘述了
# 配置熔断策略
修改熔断器的 默认配置:
# 熔断触发最小请求次数,默认值是20
hystrix.command.default.circuitBreaker.requestVolumeThreshold=10
# 熔断后休眠时长,默认值5000ms
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10000
# 触发熔断错误比例阈值,默认值50%
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
# 请求超过2s回返回错误,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
以上配置可自行尝试调用
仓库代码 : https://gitee.com/Bozhu12/spring-cloud-examples.git (opens new window)