那次 P99 延迟翻倍,锅不在模型

上个月给一个内部团队做意图分类服务的性能排查。区域监控显示 P99 延迟从 310ms 悄悄涨到 740ms,持续了大约三天才被人报警。模型没变、GPU 没变、prompt 模板也没动——第一反应是去找基础设施团队,查了一下午也没找到离群点。最后真正的原因出在请求网关层:一个上线时没有任何监控覆盖的限流中间件,把聊天后

专属插画
那次 P99 延迟翻倍,锅不在模型

那次 P99 延迟翻倍,锅不在模型

上个月给一个内部团队做意图分类服务的性能排查。区域监控显示 P99 延迟从 310ms 悄悄涨到 740ms,持续了大约三天才被人报警。模型没变、GPU 没变、prompt 模板也没动——第一反应是去找基础设施团队,查了一下午也没找到离群点。最后真正的原因出在请求网关层:一个上线时没有任何监控覆盖的限流中间件,把聊天后台的批量预处理任务和在线请求塞进了同一个连接池。

这件事本身不大,但它暴露了 AI 交付项目里三个反复出现的坑,都值得单独写下来。

第一,核心链路漏掉了"中间件层"的指标

我们整套推理服务原来的监控只打在应用层:token 数、首包时间、请求体大小。这套指标在平时很好用,但这次的问题发生在网关,应用层的每一项看起来都正常。事后我们补了三组指标:网关等待时长、连接池命中率、以及同一个租户的请求排队深度。

这里有个取舍我觉得很多团队会犹豫:中间件指标会很密,dashboard 会变得很吵。我后来的做法是,把中间件层的 P99 直接打到独立的告警通道,不进主 dashboard,避免日常噪声把真问题淹没。

第二,批量任务走同一个线程池,等于没有隔离

后台的批量生成任务用的是同一个 FastAPI 的 worker 进程。单看批量端点本身没有 bug——它就是慢,但它会阻塞整个事件循环,在线请求的延迟就直接被拖上去。等我们把批量任务拆到独立的 worker 进程之后,类似的情况就没再出现过。

拆进程的成本很低,但前提是有人问出这个问题。这次的教训是:性能 review checklist 里应该加一栏,明确列出哪些端点共用资源、哪些是隔离的,而不是每次都事后回顾。

第三,告警阈值参考的是平均值,不是分位数

最初的 P99 报警阈值是 500ms,但真正触发报警的是请求体的超时,不是 P99 指标本身。也就是说监控系统确实看到了问题,但归因指向了错误的层级,排查往错误方向走了大半天。后来把阈值改成分位数叠加结构:绝对值 600ms 报警一次,连续两个窗口超过基线 30% 再报警一次。比单一阈值敏感也不至于炸出太多误报。

修复流程值得单独固化

这次从发现问题到恢复,实际耗时 22 分钟,流程是:切网关限流开关 → 批量 worker 走独立线程池 → 观察 P99 → 收口。整个过程里没有一个步骤是我临场想的,全靠事先写下来的 runbook。

我的习惯是把"恢复方案"和"定位方案"分开维护:恢复方案是 checklist,保证压力下的动作不会跑偏;定位方案是排查路径的知识库,事后用来积累。混在一起写,通常两边都做不好。

这次的坑都不难,但每一个都需要"提前有人想到"才少踩一次。监控没有及格线,只有够不够细;隔离也不是门禁,只是资源拆分的问题。如果这次的性能排查对你有参考价值,那这些具体指标名和拆进程的判断,就是我最想留下的干货。

留言区

欢迎分享你的想法!

发表留言

0/500

加载留言中…