一、雪崩效应和断路器
雪崩效应
在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。
如果下图所示:A作为服务提供者,B为A的服务消费者,C和D是B的服务消费者。A不可用引起了B的不可用,并将不可用像滚雪球一样放大到C和D时,雪崩效应就形成了。
解决方案:
- 为网络请求设置超时,避免资源耗尽
- 使用断路器
断路器
断路器的原理很简单,如同电力过载保护器。正常情况下,断路器关闭,可正常请求服务。
在一段时间内请求失败率达到一定阈值(错误率/每分钟错误次数等),会打开断路器,其以后的多个调用快速失败,不再访问远程服务器,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。
断路器打开一段时间后,会自动进入半开状态。允许一个请求访问,如调用成功则关闭断路器。否则继续打开。
断路器开关相互转换的逻辑如下图:
Hystrix介绍
『Hystrix』是Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,提升系统可用性和容错性。
通过以下几点实现延迟和容错:
- 包裹请求,使用HystrixCommand包裹对依赖的调用逻辑,在独立线程中执行。
- 跳闸机制
- 资源隔离,为每个依赖都维护了一个小型的线程池,如线程池已满则会立即拒绝。隔离策略分为线程隔离(THREAD)和信号量隔离(SEMAPHORE)。
- 监控
- 回退机制,基于Ribbon时可在回退方法增加Throwable参数,而在Feign上可使用注解@FeignClient的fallbackFactory属性。
- 自我修复
二、Hystrix配置-基于Ribbon
1、pom.xml
1 | <dependency> |
2、@EnableCircuitBreaker
使用@EnableCircuitBreaker注解开启断路器功能
3、yml配置文件
1 | server: |
4、使用@HystrixCommand注解指定当该方法发生异常时调用的方法
1 | /** |
三、Hystrix配置-基于Feign
1、feign包含了Hystrix。
1 | <dependency> |
2、使用原有的@EnableFeignClients,不需要注解开启断路器,需要在yml上配置
3、yml配置文件,注意需要开启feign的hystrix。
1 | server: |
4、使用@FeignClient注解的fallback属性,指定fallback类
1 |
|
5、禁用方式,Feign会自动使用断路器包裹Feign客户端的方法,如需要为Feign禁用Hystrix,可通过@FeignClient的configuration属性设置配置类即可。需要全局禁用的话,直接配置feign.hystrix.enabled=false。
1 |
|
四、Hystrix监控
1、pom.xml
1 | <dependency> |
2、SpringBoot 2.0以上版本,需要设置yml
1 | management: |
3、测试
访问网页 http://localhost:8020/actuator/hystrix.stream 会不断刷新以获取实时的监控数据。如是SpringBoot是1.x版本,地址为http://localhost:8020/hystrix.stream
五、Hystrix可视化监控-Dashboard
1、pom.xml
1 | <dependency> |
2、注解@EnableHystrixDashboard
3、yml配置文件
1 | spring: |
4、测试
访问网页 http://localhost:8030/hystrix 可以看到如下网页。
并输入需要监控的地址 http://localhost:8020/actuator/hystrix.stream ,见上节。
刷新几次接口,可以看到如下统计图标数据。
六、Hystrix监控集群-Turbine
在复杂的分布式系统中,相同服务的节点经常需要部署上百甚至上千个,很多时候,运维人员希望能够把相同服务的节点状态以一个整体集群的形式展现出来,这样可以更好的把握整个系统的状态。 为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。
1、pom.xml
1 | <dependency> |
2、注解@EnableTurbine,激活对Turbine的支持。
3、yml配置文件
1 | server: |
4、测试
访问网页 http://localhost:8031/tuibine.stream 会不断刷新以获取实时的监控数据。
后续可同样通过Dashboard来设置如上地址查看可视化页面。
七、服务降级、限流
Hystrix隔离策略
线程池隔离 | 信号量隔离 | |
---|---|---|
线程 | 与调用线程非相同线程 | 与调用线程相同(jetty线程) |
开销 | 排队、调度、上下文开销等 | 无线程切换,开销低 |
异步 | 支持 | 不支持 |
并发支持 | 支持(最大线程池大小) | 支持(最大信号量上限) |
Hystrix默认使用THREAD策略,当请求的服务网络开销比较大的时候,或者是请求比较耗时的时候,我们最好是使用线程隔离策略,这样的话,可以保证大量的容器(tomcat)线程可用,不会由于服务原因,一直处于阻塞或等待状态,快速失败返回。而当我们请求缓存这些服务的时候,我们可以使用信号量隔离策略,因为这类服务的返回通常会非常的快,不会占用容器线程太长时间,而且也减少了线程切换的一些开销,提高了缓存服务的效率。
Hystrix的参数配置
Hystrix提供了如下的几个关键参数,来对一个熔断器进行配置,每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
1 | circuitBreaker.requestVolumeThreshold //滑动窗口的大小,默认为20 |
服务降级
有了熔断,就得有降级。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。
服务限流
比如在Hystrix中,如果是线程隔离,可以通过线程数 + 队列大小限制;如果是信号量隔离,可以设置最大并发请求数。
另外一个常见的策略就是根据QPS限制,比如我知道我调用的一个db服务,qps是3000,那如果不限制,超过3000,db就可能被打爆。这个时候,我可用在服务端做这个限流逻辑,也可以在客户端做。