服务雪崩
假设存在如下调用链
而此时,Service A
的流量波动很大,流量经常会突然性增加!那么在这种情况下,就算Service A
能扛得住请求,Service B
和Service C
未必能扛得住这突发的请求。
此时,如果Service C
因为抗不住请求,变得不可用。那么Service B
的请求也会阻塞,慢慢耗尽Service B
的线程资源,Service B
就会变得不可用。紧接着,Service A
也会不可用,这一过程如下图所示
如上图所示,一个服务失败,导致整条链路的服务都失败的情形,我们称之为服务雪崩。
那么,服务熔断和服务降级就可以视为解决服务雪崩的手段之一
服务熔断
服务熔断:当下游的服务因为某种原因变得突然不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用
需要说明的是熔断其实是一个框架级的处理,那么这套熔断机制的设计,基本上业内用的是断路器模式
,如下图所示
- 最开始处于
closed
状态,一旦检测到错误到达一定阈值,便转为open
状态; - 这时候会有个 reset timeout,到了这个时间了,会转移到
half open
状态; - 尝试放行一部分请求到后端,一旦检测成功便回归到
closed
状态,即恢复服务;
业内目前流行的熔断器很多,例如阿里出的Sentinel,以及最多人使用的Hystrix
在Hystrix中,对应配置如下
1 | # 滑动窗口大小,默认是20 |
每当20个请求中,有50%失败后,熔断器就会打开,此时再调用服务,将会直接返回失败,不再调远程服务。直到5s后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
这些属于框架层级的实现,我们只要实现对应接口就好!
服务降级
下面有两种场景
- 当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度
- 当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户
其实要这么理解 - 服务降级有很多种降级方式!如开关降级、限流降级、熔断降级
- 服务熔断属于降级方式的一种
从实现上来说,熔断和降级必定是一起出现。因为当发生下游服务不可用的情况,这个时候为了对最终用户负责,就需要进入上游的降级逻辑了。因此,将熔断降级视为降级方式的一种
服务降级大多是属于一种业务级别的处理。当然,这里要讲的是另一种降级方式,也就是开关降级,这也是我们生产中常用的另一种降级方式
做法很简单,做个开关,然后将开关放在配置中心,在配置中心更改开关,决定哪些服务进行降级。
那么,在应用程序中部下开关的这个过程,业内也有一个名词,称为埋点!
那接下来最关键的一个问题,哪些业务需要埋点?一般有以下方法:
- 简化执行流程
自己梳理出核心业务和非核心业务流程,然后在非核心业务流程加上开关,一旦发现系统扛不住,关掉开关,结束这些次要流程 - 关闭次要功能
一个微服务下肯定有很多功能,那自己区分出主要功能和次要功能。然后次要功能加上开关,需要降级的时候,把次要功能关了 - 降级一致性
假设,你在业务上发现执行流程没法简化了,愁啊!也没啥次要功能可以关了,桑心啊!那只能降低一致性了,即将核心业务流程的同步改异步,将强一致性改最终一致性!
总结
背景
分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务,如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。
雪崩效应常见场景
- 硬件故障:如服务器宕机,机房断电、光纤被挖断等
- 流量激增:如异常流量,重试加大流量
- 缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用
- 程序BUG:如程序逻辑导致内存泄漏,JVM长时间FullGC等
- 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽
雪崩效应应对策略
针对造成雪崩效应的不同场景,可以使用不同的应对策略,没有一种通用所有场景的策略,参考如下:
- 硬件故障:多机房容灾、异地多活等
- 流量激增:服务自动扩容、流量控制(限流、关闭重试)等
- 缓存穿透:缓存预加载、缓存异步加载等
- 程序BUG:修改程序bug、及时释放资源等
- 同步等待:资源隔离、MQ解耦、不可用服务调用快速失败等。资源隔离通常指不同服务调用采用不同的线程池;不可用服务调用快速失败一般通过熔断器模式结合超时机制实现
综上所述,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处于被拖垮的风险中。因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护意识,当依赖服务不可用时,当前服务启动自动保护功能,从而避免发生雪崩效应。