项目-服务降级
April 3, 2025About 5 min
背景
有次突然有大主播和另外一个大主播联动开播,但是由于运营没有及时通知业务部门,导致业务部门这边没有提前准备,导致大流量过来把服务打崩;
背景是这样的,由于出了这个事情,我们为了防止这种突发流量做了下面的处理:
- 代码针对各个业务做了服务降级;
- 对于 IM 业务做了上下行限流;
- 在运维层面做了弹性扩容;
级联故障案例:如果有 A 和 B 两个服务,A 调用 B 服务,如果 B 服务出现问题了,如果此时 A 还有大量的调用 B 的请求,就可能导致 A 也会出现问题,新来的请求导致线程数不断增加。
优化目标
此处只说服务降级的目标
- 针对不同的业务,能够在大流量时候关闭非核心业务;
- 服务调用自动降级;
- 人工手动降级;
问题分析思路/过程
自动降级的方案 Sentinel、Hystrix
有两种隔离方案:
- 线程池隔离:线程池隔离实际上就是对每个服务的远程调用单独开放线程池,比如服务A要调用服务B,那么只基于固定数量的线程池,这样即使在短时间内出现大量请求,由于没有线程可以分配,所以就不会导致资源耗尽了;
- 信号量隔离:使用 Semaphore 类(许可证)实现的,思想基本上与上面是相同的,也是限定指定的线程数量能够同时进行服务调用,但是它相对于线程池隔离,开销会更小一些,使用效果同样优秀,也支持超时等。Sentinel 也正是采用的这种方案实现隔离的。
当下游服务因为某种原因变得不可用或响应过慢时,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务而是快速返回或是执行自己的替代方案,这便是服务降级。
Sentinel 中有三种策略:
- 慢调用比例
- 异常比例
- 异常数
降级方法:@SentinelResource中配置blockHandler参数
手动降级处理
降级的原理就是降低次要功能的可用性实用性,增加核心功能的高可用性。
降级的种类:
- 根据降级的种类可以分为 ①服务端代码开关降级;② 开关前置降级;
- 根据读写性质可以分为 ① 读降级;② 写降级;
- 根据降级的性质可以分为 ① 内容降级;② 限流降级;
- 根据维护降级可以分为 ① 手动降级 ② 监控自动降级;
根据降级的种类可以分为:
- 服务端代码开关降级,就是一些配置开关,对于非核心的功能进行入口关闭,或者精简返回的内容;
- 开关前置降级
- 可以把配置开关通过提供服务端的接口,返回给客户端一些配置开关信息,客户端哪里去做降级;
- 或者可以在 Nginx 做降级处理;(Nginx 有可以通过 lua 脚本去处理)
- 或者业务网关层做降级处理;
根据读写性质可以分为:
- 读降级怎么做?比如礼物信息,一般是不会频繁改变的,本来是可以通过读 Redis + MySQL 的策略,在大流量情况下可以允许直接读取持久的 Redis 数据,或者本地缓存的数据;
- 写降级怎么做?针对非核心业务,可以把直接写入 MySQL 的数据先临时保存起来。
- 例如有很多插入一条数据的操作。可以把这些操作数据传到 Kafka,然后存到 redis,等到 redis 中的数据存到了 10 条,或者 100 条,就可以批量插入数据库了;
根据降级的性质可以分为:
- 内容降级:精简返回的数据;
- 限流降级:通过一些算法进行限流,或者直接告知系统维护;
根据降级的维护:
- 手动降级:是人为看到系统负载异常后,手动调整降级;
- 主要是一些配置开关,可以直接去 Nacos 的控制台改。
- 因为 Nacos 可以通过服务端代码去修改配置的能力,可以通过调接口批量修改开关;
- 自动降级:是系统监测到异常后,自动降级。自动降级虽然更加智能,但有时候自动脚本可能会干一些超乎预料的事情。
- 阿里云可以监控系统的 CPU 和内存等指标,当触发到某个阈值一段时间后可以去执行一些操作,比如发钉钉消息等,其实也可以去触发一些脚本,比如调用前面说的 Nacos 代码修改配置的接口;
- 大多数情况下的手动降级也可以做成自动的方式,可以根据各种系统指标设定合理阈值,在相应指标达到阈值上限自动开启降级。在很多场景下,由于业务过于复杂,需要参考的指标太多,自动降级实现起来难度会比较大,而且也很容易出错。
- 但是这种可能某些无关紧要的异常导致的指标异常,这时去触发服务降级,可能会给用户带来不好的体验;
Contributors
Dylan Kwok