线上故障-组件降级

一、背景

故障现象:一个C端组件有概率不展示

根本原因:线程池队列长度配置不合理,导致强依赖数据无法获取到,失败降级。

二、分析

简单分析一下代码逻辑:

menu是聚合层服务,需要分别从domain1和domain2两个领域服务请求数据,组装后返回。

对性能要求比较高,使用线程池进行了并行rpc请求。

一次请求需要发起对这两个服务共四次rpc请求,其中三个是强依赖请求domain1,一个是弱依赖请求domain2

其中线程池是这样配置的:四个任务都使用同一个线程池;线程池队列核心线程数为10,长度为500.

在当天出现了爆品,导致流量异常上涨,domain2服务接口RT上涨(机器指标无异常,也是线程池排队导致RT上涨)

menu线程池的核心线程无法及时获得domain2接口的返回,导致了任务堆积的情况,

导致domain1的强依赖接口无法得到及时的处理。

定位到问题,发现domain2的接口RT上涨明显,对服务进行了扩容,接口成功率回升。

三、教训

  1. 非新上线代码,优先扩容观察。
  2. 线程池队列不能配置太大。
  3. 线程池共用时需要区分强弱依赖。
  4. 核心链路重要线程池出现任务积压时需要告警。
  5. 流量异常上涨需要及时感知。

附:

虽然这个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的抖动影响,以及耗时长的任务的影响


线上故障-组件降级
https://yzaf.top/2023/coe/coe-executor/
作者
why
发布于
2023年9月30日
许可协议