用 httpx 0.27 写异步客户端调推理服务,并发 200 时日志开始刷 PoolTimeout,原文是 The connection pool is full, consider increasing max_connections,但把超时从 5 秒调到 30 秒只是让报错晚一点出现。
一开始怀疑是「超时只加在 read 上,等连接池的阶段用的是另一个超时参数」,查了一圈,方向不对。
原因不止一个,得分开看。默认 Limits 的 max_connections 是 100,200 个协程同时在等连接槽。也可能是流式请求拿到连接后一直不释放,直到生成结束才归还。
还有一种情况,没有限制并发信号量,协程数量远超连接池容量。
第一件事是把连接池上限和超时一起显式配置
python -c "import httpx;print(httpx.Limits(max_connections=256,max_keepalive_connections=64))" || pip install -U httpx
随后用信号量把在途请求数压到连接池容量以内
python -c "import asyncio;sem=asyncio.Semaphore(200);print(sem._value)"
然后对每个流式响应显式关闭以归还连接
python -c "print('async with client.stream(...) as r:')"
压测里统计等待连接的时间占比
python bench_pool.py --concurrency 200 --url http://127.0.0.1:8000/v1/chat/completions
恢复的判定其实很直接。并发 200 时 PoolTimeout 计数为 0,连接池的 wait 时间 P99 低于 20ms,池内活跃连接数不超过 max_connections。
提醒一点。池子大小要和下游真实承载能力对齐,一味放大只会把压力原样推给上游,报错从客户端转移到服务端并不算修好。这类问题最好一次改到位,反复小改反而容易把原因搅混。
