推理网关先把请求放进内存队列再转发,上游限流后队列没有上限,压测半小时队列涨到十二 GB,进程被 OOM killer 杀掉,重启后积压请求全丢,客户端只看到连接被重置。

一开始怀疑是「队列只存在进程内,重启即丢」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。内存队列没有上限,生产速度长期高于消费速度。还有一种是队列满时没有拒绝,仍然继续接收并堆积。

不容易想到的是,缺少队列长度告警,涨到崩溃前没人发现。

第一件事是确认队列长度与内存占用的关系

python -c "import psutil;print(psutil.Process().memory_info().rss/2**30)"

给队列设上限并在满时返回 429

curl -s -o /dev/null -w '%{http_code}' -X POST http://gw:8080/v1/chat -d @req.json

接着把非核心请求降级为快速失败

python gw.py --queue-max 2000 --on-full reject --retry-after 2

压测确认进程内存不再增长

python loadtest.py --rps 200 --duration 900 --watch-rss

别只看报错消失,验证要多做一步。队列到两千条后新请求立刻拿到带 Retry-After 的 429,进程内存稳定在四 GB 以内,压测全过程没有重启。

背压的本质是尽早把压力退回给调用方,队列无上限只是把崩溃从入口推迟到内存耗尽那一刻。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189