Spring Cloud之熔断器Hystrix
断路器的概念
有一条山路,被山洪冲垮了,但是大家都不知道。车辆还是沿着山路前进,直到被挡住了去路才发现此路不通,但是此时路上车太多了,前面的车走不了也退不回来,后面的车还在源源不断的开过来,所有人都挤在山上不能动。后来有人就制作了一个提示牌——“此路不通,车辆绕行”。以后每次山路被冲毁的时候,都把这块牌子立在山脚,来往的车辆一看见这牌子就掉头回去了。
这块牌子就是一个断路器,这条山路就是一个服务组件。平时服务组件正常访问的时候断路器不发挥作用,但是一旦服务组件运转异常,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。断路器的作用就显现出来了,断路打开后,可用避免连锁故障,fallback 方法可以直接返回一个固定值。
Hystrix
Hystrix,英文意思是豪猪,全身是刺,刺是一种保护机制。Hystrix 也是 Netflix 公司的一款组件。
Hystrix 的作用:实现服务熔断降级处理,保护微服务,防止雪崩效应发生。
Hystrix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应。
雪崩效应
什么是雪崩效应?
分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。
对大部分电商和快递公司来说,每年年底(Q4 季度)由于双 11 等大促活动的存在,将面对大量的用户流量,尤其是属于大促的那几天,无论是用户的商品订单还是物流订单,都将是平时的 3 倍以上。
如果这个时候,单个服务出现问题,调用这个服务就出现线程阻塞,此时若有大量的请求涌入,容器的线程资源就会被消耗完毕导致服务瘫痪。
对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成不可估量的严重后果,这就是常说的服务故障的“雪崩效应”。
为了解决这个问题,有人就提出了一种解决问题的思路,断路器模型。就是每一个调用服务的接口处加一个断路器,默认是关闭的,当对服务调用时,不可用的次数达到一个阀值时,断路器就会打开,通过回调方法迅速返回一个值结束调用,避免出现连锁故障。
综上所述,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处在被拖垮的风险中。 因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护能力,当依赖服务不可用时,当前服务启动自我保护功能,从而避免发生雪崩效应。
熔断器的原理
熔断器状态机有 3 个状态:
熔断器有三个状态 CLOSED、 OPEN、HALF_OPEN 。
熔断器默认关闭状态,当触发熔断后状态变更为 OPEN,在等待到指定的时间,Hystrix 会放请求检测服务是否开启,这期间熔断器会变为 HALF_OPEN 半开启状态,熔断探测服务可用则继续变更为 CLOSED 关闭熔断器。
- Closed:关闭状态,所有请求正常访问
- Open:打开状态,所有请求都会被降级
Hystrix 会对请求情况计数,当一定时间失败请求百分比达到阈值,则触发熔断,断路器完全关闭,默认失败比例的阈值是 50%,请求次数最低不少于 20 次
- Half Open:半开状态
Open 状态不是永久的,打开一会后会进入休眠时间(默认 5 秒)。休眠时间过后会进入半开状态。
半开状态:熔断器会判断下一次请求的返回状况,如果成功,熔断器切回 closed 状态。如果失败,熔断器切回 open 状态。
熔断器的核心
- 线程隔离
- 线程隔离:是指 Hystrix 为每个依赖服务调用一个小的线程池,如果线程池用尽,调用立即被拒绝,默认不采用排队
- 服务降级
- 服务降级(兜底方法):优先保证核心服务,而非核心服务不可用或弱可用。触发 Hystrix 服务降级的情况:线程池已满、请求超时
线程隔离和服务降级之后,用户请求故障时,线程不会被阻塞,更不会无休止等待或者看到系统奔溃,至少可以看到执行结果(熔断机制)。
局部熔断/服务降级案例
目标:服务提供者的服务出现了故障,服务消费者快速失败给用户友好提示。体验服务降级
降级:某个方法发生故障,则返回默认的数据给用户,此时叫服务降级。其他方法可用,该方法不可用 ,只是降低权限
实现步骤
1、引入熔断的依赖坐标
在user-consumer
中加入依赖
1 | <!--熔断器--> |
2、开启熔断的注解
修改user-consumer
的UserConsumerApplication
,在该类上添加@EnableCircuitBreaker
1 |
|
注意:这里也可以使用@SpringCloudApplication
,写了@SpringCloudApplication
后,其他注解需要全部去掉。
3、服务降级处理
在user-consumer
的UserController
中添加降级处理方法
1 | /**** |
在有可能发生问题的方法上添加@HystrixCommand
注解来使用降级处理调用,例如在queryById
方法上添加降级调用
1 |
|
启动eureka-server
和user-consumer
还有 user-provider
请求:http://localhost:18082/consumer/3
其他熔断策略配置
熔断后休眠时间:sleepWindowInMilliseconds
熔断触发最小请求次数:requestVolumeThreshold
熔断触发错误比例阈值:errorThresholdPercentage
熔断超时时间:timeoutInMilliseconds
在 user-consumer
配置如下:
1 | # 配置熔断策略: |
全局服务降级的 fallback 方法
两种编写方式:编写在类上,编写在方法上。
在类的上边对类的所有方法都生效。在方法上,仅对当前方法有效。
1、方法上服务降级的 fallback 兜底方法
1 | // 使用HystrixCommon注解,定义 |
2、类上默认服务降级的 fallback 兜底方法
1 | // 刚才把fallback写在了某个业务方法上,如果方法很多,可以将FallBack配置加在类上,实现默认FallBack |
添加一个全局熔断方法,.在queryById
方法上只添加@HystrixCommand
注解,在类上添加@DefaultProperties
注解及内容
1 |
|