高并发架构:熔断和降级
熔断和降级,还有上一章提到的限流,都是服务容错的设计。分布式架构中如果没有良好的容错设计,一旦链路上某个服务发生故障,很容易引发雪崩效应。
例如业务链路上某服务响应缓慢,那么依赖它的上游服务也会延迟响应,如此一级一级向上传递,导致整个业务都出现响应缓慢的问题,严重时还可能出现拒绝服务的情况。
熔断和降级,就是为了避免上述问题的出现。
降级
由于爆炸性的流量冲击,对一些服务进行有策略的放弃,以此缓解系统压力,保证目前主要业务的正常运行。它主要针对非正常情况下的应急服务措施:当此时一些业务服务无法执行时,给出一个统一的返回结果。
服务降级的特征
- 原因:系统整体负荷超出其承载能力;
- 目的:保证重要或基本服务的运行,非核心服务延迟使用或暂停使用;(弃车保帅)
- 粒度:降低服务粒度,将降级粒度控制在合理范围内;
- 可控性:可分为手动降级和自动降级。在服务侧有开关配置,允许人工介入;
- 次序:服务配置优先级。先把优先级最低的服务降级;
降级方式
- 延迟服务:比如论坛的发表评论服务是重要服务,需要有限保证,但评论完增加积分是次要业务,可以先把请求放到缓存中,等服务平稳之后再执行;
- 在粒度范围内关闭服务:比如关闭相关的商品推荐,返回静态资源,或者直接关闭推荐区;
- 页面异步请求降级:比如订单页面上展示的物流信息如果接口返回缓慢,可以先不调用;
- 页面跳转(页面降级):前端直接不去家在某个页面,而是直接跳转到固定地址。如秒杀活动,可以直接跳转到“人太多请稍后重试”的页面上;
- 写降级:比如秒杀抢购,我们可以只进行 Cache 更新,然后异步扣件库存到 DB,保证最终一致性即可,此时是将 DB 降级为 Cache;
- 读降级:比如多级缓存模式,如果后端服务有问题,可以降级为只读缓存,这种方式适用于对读一致性不高的场景;
降级分类
按照是否自动化可分为自动降级和手动降级。自动降级一般是系统检测到下游服务有异常情况而采取的措施,手动降级则是综合考虑系统整体负载而做出的取舍策略。
自动降级
自动降级是系统自发的行为,因此自动降级也需要伴随一定的自动恢复策略,否则运维人员就炸锅了。
- 超时降级:配置好下游服务的超时时间和重试次数,达到阈值后进行降级,降级后使用异步机制探测服务恢复情况;
- 失败次数降级:下游不稳定的 api,当失败调用次数达到一定阈值后进行的降级;
- 故障降级:下游服务挂了(网络故障、RPC 服务异常等),直接进行降级。降级后可以返回默认值、兜底数据或者从缓存中读取;
- 限流降级:下游达到限流阈值后进行降级,降级后的处理方案可以是:排队页面、错误页面等;
熔断
熔断是指请求下游服务失败或响应时间过长的数量达到阈值,上游服务主动断开,不再继续调用下游服务。熔断是降级的一种,对应上面提到的自动降级。
断路器(Curcuit Breaker)
断路器模式是实现熔断的方式。断路器就像电气系统里的保险丝,把错误隔离,防止出现服务雪崩。
基本断路器的结构如下图:
它有两种状态(close 和 open)和一个基本 trip 动作:
- close 状态下,断路器不工作,client 向 supplier 发起的请求直接无阻碍通过断路器,supplier 返回的结果也直接通过断路器到达 client,相当于断路器不存在;
- open 状态下,client 向 supplier 发起的请求会被断路器拦截,直接返回 client,此时断路器无法通过;
- trip 动作:是指断路器在 close 状态下,如果 supplier 持续报错或超时,达到规定的阈值后,断路器由 close 转为 open 状态的动作。
基本模式的断路器,自身没有自动恢复的操作,需要外界介入。扩展模式的断路器结构如下图:
相比基本断路器,扩展断路器增加了一个半开状态:
- HALF-OPEN:断路器自动恢复的状态。当断路器 OPEN 状态一段时间后,将“自动”(一般是由下一次请求而不是计时器触发的,所以这里自动带引号)切换到 HALF OPEN 状态。该状态下,会放行一次远程调用,然后根据这次调用的结果成功与否,转换为 CLOSED 或者 OPEN 状态,以实现断路器的弹性恢复。
方案
- Spring Cloud Netflix Hystrix 就是隔离措施的一种实现,可以设置在某种超时或者失败情形下断开依赖调用或者返回指定逻辑,从而提高分布式系统的稳定性。
- Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。