报错是这么冒出来的。移动端把请求超时设成 5 秒,用户切走页面后连接断开,但 vLLM 日志里这条请求继续跑到 900 个 token 才结束,GPU 被白白占了十几秒,同时间其他请求的排队明显变长。
中间走过弯路,把「中间 nginx 没有配 proxy_ignore_client_abort,断连后仍把请求转发完」当成主因,改完现象没变。
真正麻烦的地方在于,几个原因的现象几乎一样。FastAPI 只在返回响应时才发现连接已断,生成过程中没有检查断开状态。少数情况下是生成的循环用的是同步 SDK,取消信号传不进推理引擎。
少数情况下是客户端的 abort 只关了 TCP,服务端 read 循环没触发任何异常。
上来先在流式生成循环里穿插检查连接是否还在
python -c "from fastapi import Request;print('await request.is_disconnected()')"
随后让 nginx 在客户端断开后同步取消上游
sed -i '/location \/v1\//a\ proxy_ignore_client_abort off;' /etc/nginx/conf.d/ai.conf && nginx -s reload
断连后打印一次计数确认取消路径生效
python -c "import logging;logging.basicConfig(level=logging.INFO);logging.info('abort seen')"
等前面都确认过,再用 curl 主动超时复现并对比 GPU 占用时长
curl --max-time 2 http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"qwen","max_tokens":900,"messages":[{"role":"user","content":"写长文"}]}'
恢复的判定其实很直接。curl 2 秒断开后服务端日志 1 秒内出现 abort 记录,vllm:num_requests_running 立刻回落,GPU 显存与利用率在 3 秒内回到空闲水平。
取消链路要端到端打通,代理层默认忽略客户端中断,只改应用代码往往看不到效果,先从最外层的一端关掉。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
