先把当时的情况摆出来。内部网关到推理服务开了 keep-alive,空闲 90 秒后的第一批请求有百分之三返回 502,nginx 错误日志写 upstream prematurely closed connection while reading response header,重发一次就正常。
原因不止一个,得分开看。上游 keepalive_timeout 比网关的连接池空闲时间短,连接已被对端关掉。也可能是网关把失效连接留在池里没有做健康检查,复用时才发现已经断了。
另外,HTTP/1.1 没带 Connection 头,两边对长连接的理解不一致。少数情况下是容器重启后旧连接的 fd 还在池中,指向的是新进程之外的端口。
上来先把两侧的空闲超时排开,让网关先回收
grep -E 'keepalive_timeout|keepalive_requests' /etc/nginx/nginx.conf
接着在上游块里显式声明长连接池并限制空闲数
printf 'upstream llm {\n server 127.0.0.1:8000;\n keepalive 32;\n}\n' >> /etc/nginx/conf.d/upstream.conf && nginx -t
再往下用 curl 连续两次间隔复用同一连接验证
curl -s -o /dev/null -w '%{http_code} %{time_connect}\n' http://127.0.0.1/v1/models http://127.0.0.1/v1/models
压测里加 2% 的坏连接注入看是否还会 502
python soak.py --rps 20 --duration 300 --error-budget 0.001
恢复的判定其实很直接。持续压测十分钟内 502 计数为 0,nginx 日志不再出现 prematurely closed,网关连接池里的空闲连接数与 keepalive 上限相符。
长连接不是越长越好,两边超时必须有明确的大小关系,谁先关谁负责重连,否则总会有一小撮请求撞在关闭瞬间。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
