本文介绍了 Prometheus 插件造成长尾请求现象的原因,以及如何解决这个问题。
作者屠正松,Apache APISIX PMC Member。
现象
在 APISIX 社区中,曾有部分用户陆续反馈一种神秘现象:部分请求延迟较长。具体表现为:当流量请求进入一个正常部署的 APISIX 集群时,偶尔会出现部分请求有 1 ~ 2 秒的延迟。用户的 QPS 规模大概在 1 万,但是这种异常请求非常少见,每隔几分钟就会出现 1 ~ 3 次。一些用户在 issue 中也提供了捕获到的延迟较长的请求。从这些截图中可以看出,确实有请求延迟较高,甚至可以达到秒级别。
这种现象伴随着另一种现象:某个 worker 进程的 CPU 占用率达到了 100%。
开发团队通过不同渠道与这些反馈的用户沟通得知,这个现象发生的条件是:
- 开启 prometheus 插件,并且有 Prometheus Exporter 访问 APISIX 的 endpoint
/apisix/prometheus/metrics
来采集指标; - prometheus 插件统计的 metrics 的数量达到一定规模,通常是上万级别;
这个现象是在业界称为 “长尾请求”,是指在一个请求群体中,大部分请求响应时间较短,但有少部分请求响应时间较长的情况。它可能是由于后端系统的性能瓶颈、资源不足或其他原因导致的。它不是一个致命的 bug,但是它严重影响了终端用户的体验。
抽丝剥茧
APISIX 基于一个开源的 Lua 库 nginx-lua-prometheus 开发了 Prometheus 插件,提供跟踪和收集 metrics 的功能。当 Prometheus Exporter 访问 APISIX 暴露的 Prometheus 指标的 endpoint 时,APISIX 会调用 nginx-lua-prometheus 提供的函数来暴露 metrics 的计算结果。
开发团队从社区用户,企业用户等渠道收集汇总了长尾请求发生的条件,基本定位了问题所在:nginx-lua-prometheus 中用于暴露 metrics 指标的函数 prometheus:metric_data()
。
不过这只是初步推断,还需要直接的证据来证明长尾请求与此有关,并且需要搞清楚以下问题:
- 这个函数具体做了什么?
- 这个函数为什么会造成长尾请求现象?
开发团队构造了本地复现环境,这个复现环境主要模拟以下场景:
- 模拟客户端发送正常请求,被 APISIX 代理到上游
- 模拟 Prometheus Exporter 每隔 5 秒访问
/apisix/prometheus/metrics
,触发 APISIX 运行prometheus:metric_data()
函数
复现环境示意图: