You need to enable JavaScript to run this app.
导航
可控延时队列
最近更新时间:2024.06.06 15:35:42首次发布时间:2024.06.06 14:31:42

背景

在某业务场景中,实例日常的处理能力在 1100/s,CPU 使用率在 50% 左右。
当请求突增长到 1500/s 时,几分钟之内,延时从 150ms 变得几乎都超时、请求堆积,CPU 使用率达到 100%,所有请求几乎完全不可用。
图片

问题现象

请求从 1100/s 增加到 1500/s,QPS 也就增加了 40%~50%(甚至更少),为何延时、 CPU 使用率没呈比例放大,而是接近崩溃?
理想条件下,在实例原本处理能力范围内的请求应该成功,只是新增的那部分请求失败,为何全部请求都几乎失败?

问题分析

核心影响因素是:实例内部队列堆积线程过多
示例:
假设处理能力是 1300/s,接收的请求却是 1500/s,那么每秒就堆积了 200 个请求。
实例默认队列大小为 1000 个,在该示例中,5s 就可以将实例队列堆满,此时实例会启用 CPU core*1.5(上限)的线程数来执行查询请求,CPU 使用率立马就提升。
由于 CPU 负载很高、线程很多、存在线程争用,此时单个请求的处理延时会高于平时耗时的数倍,进一步降低了集群处理能力。

解决方案

从实例内部队列中拿出请求后,如果是 search 相关的请求,需要先判断已经在队列里等待的时间,超过一定时间(默认10s),则失败返回,而不是继续执行。
作出以上处理的判断原因有以下两条:

  • 因为上游早就超时了。
    比如日常请求的处理耗时为 200ms,CPU 使用率 100% 时的请求耗时是 1s。如果要处理完整个队列的请求,差不多需要要 20 多分钟,已经没有进一步处理的意义。
  • 方便集群的快速恢复。
    如果实例的队列堆积需要 20 多分钟才能完全恢复,对很多业务来说显然是不可以接受的。这时如果要快速恢复,只能重启整个实例,但是实例重启的代价很高。选择不执行队列中的超时请求,是最快速恢复的最优处理办法。

支持动态更新 search 队列中的超时时间。命令如下:

PUT _cluster/settings
{
    "persistent": {
        "thread_pool.search.queue_wait_timeout":"30s"
    }
}

常见问题

如果您在更新可控延迟队列超时参数的过程中遇到难以解决的问题,可以通过提交工单进行咨询。详情请参见技术支持