线上故障-组件降级
一、背景
故障现象:一个C端组件有概率不展示
根本原因:线程池队列长度配置不合理,导致强依赖数据无法获取到,失败降级。
二、分析
简单分析一下代码逻辑:
menu是聚合层服务,需要分别从domain1和domain2两个领域服务请求数据,组装后返回。
对性能要求比较高,使用线程池进行了并行rpc请求。
一次请求需要发起对这两个服务共四次rpc请求,其中三个是强依赖请求domain1,一个是弱依赖请求domain2
其中线程池是这样配置的:四个任务都使用同一个线程池;线程池队列核心线程数为10,长度为500.
在当天出现了爆品,导致流量异常上涨,domain2服务接口RT上涨(机器指标无异常,也是线程池排队导致RT上涨)
menu线程池的核心线程无法及时获得domain2接口的返回,导致了任务堆积的情况,
导致domain1的强依赖接口无法得到及时的处理。
定位到问题,发现domain2的接口RT上涨明显,对服务进行了扩容,接口成功率回升。
三、教训
- 非新上线代码,优先扩容观察。
- 线程池队列不能配置太大。
- 线程池共用时需要区分强弱依赖。
- 核心链路重要线程池出现任务积压时需要告警。
- 流量异常上涨需要及时感知。
附:
虽然这个500是历史逻辑
但是我也没有思考过线程池队列长度的合理配置(虽然不是我配的 但我也未必不会这么配
先计算一下500为什么不行?
假设队列排满了,长度500,10个核心线程,最后的任务需要等待处理 500/10=50 轮任务,
假设任务的平均时长是50ms(对于一个rpc接口,已经不算长了),那么最后的任务需要等待2.5s才能轮到自己执行。
2.5s显然不能接受。
那按照这个逻辑,比较合理的队列长度是多少呢?
首先考虑我这个任务能接受多长的等待时间?
对于这个场景,对返回时间比较敏感,最多可以接受100ms等待时间。
那么就是2轮任务,所以队列长度配置为核心线程的2倍比较合理。
那核心线程数应该怎么计算呢?
理论上我们需要能保持核心线程数处理能力 > 新增任务的数量
在这个场景,假设不分拆弱依赖线程池,那么1qps的单机请求,就会导致4qps的任务,
一个核心线程在1s可以处理 1s /50ms = 20个任务,因此核心线程数至少为 单机请求qps * 4 / 20
(这里要考虑RT的抖动影响,以及耗时长的任务的影响