【Bug已解决】[Bug]: API Connection Error after concurrent API calls 解决方案
【Bug已解决】[Bug]: API Connection Error after concurrent API calls 解决方案一、现象长什么样用客户端高并发打 vLLM 的 OpenAI 兼容 API/v1/chat/completions或/v1/completions时并发量一上去就出现连接错误requests.exceptions.ConnectionError: (Connection aborted., BrokenPipeError(...))或aiohttp.client_exceptions.ClientOSError: [Errno 24] Too many open files或客户端侧httpx.ConnectError: [Errno 60] Operation timed out几个典型表征只在并发高时出现串行/低并发正常说明问题在连接数 / 文件描述符 / 端口复用这类资源上限而非单次请求逻辑。错误是连接层ConnectionError / BrokenPipe / Too many open files不是业务层服务端可能在高并发下用完了文件描述符fd、或没用 keep-alive 导致 TIME_WAIT 堆积、或事件循环被连接建立压垮。服务端可能伴随OSError: [Errno 24] Too many open files这是典型 fd 耗尽每个 TCP 连接占一个 fd并发数 × 每请求连接数超过系统ulimit -n。这不是模型问题而是API server 的连接/资源处理能力在高并发下被耗尽。下面给出定位与修复客户端连接池 服务端 fd/keep-alive 调优。二、背景HTTP 服务在高并发下的连接资源每个 TCP 连接占用一个文件描述符fd。Linux 默认ulimit -n可能是 1024vLLM 的 uvicorn/fastapi 进程若并发接几千连接fd 直接耗尽 →Too many open files→ 新连接被拒 / BrokenPipe。短连接无 keep-alive会留大量 TIME_WAIT每个请求建连断连端口/连接表堆积导致Cannot assign requested address或连接超时。客户端没用连接池每次请求新建requests.Session/ 新httpx.Client连接不复用fd 暴涨。vLLM 默认用 uvicorn 起服务并发连接上限受 fd 和系统 backlog 影响。修复分两端服务端调大ulimit -n、开 keep-alive、限制并发或靠队列排队而非无限制接连接客户端用连接池requests.Session/httpx.AsyncClient复用 限并发 指数退避重试。下面用可运行代码实现客户端连接池 服务端 fd 检测。三、根因拆成三条根因fd 耗尽服务端并发连接数超过进程 fd 上限默认 1024新连接accept失败 →Too many open files/ BrokenPipe。根因是服务端 fd 上限过低 短连接不回收。客户端不复用连接客户端每次请求新建连接没用 Session/Client连接数 请求数fd 在服务端和客户端同时暴涨。根因是缺少连接池 keep-alive 复用。无并发限制 / 重试风暴客户端无脑并发 失败后立刻重试连接数在重试中指数放大把服务端压垮。根因是缺少并发上限 退避重试。修复方向服务端调大 fd 开 keep-alive客户端用连接池复用 Semaphore限并发 指数退避重试。四、最小可运行复现下面复现客户端无连接池导致连接数暴涨的判定逻辑import threading class NaiveClient: 现状每次请求都建新连接连接不复用。 def __init__(self): self.open_connections 0 self._lock threading.Lock() def request(self): with self._lock: self.open_connections 1 # 每次新建 # ... 真实请求 ... with self._lock: self.open_connections - 1 def simulate_concurrent(client, n): threads [] def job(): # 串行化统计峰值朴素客户端峰值 ≈ 并发数 client.request() for _ in range(n): t threading.Thread(targetjob); t.start(); threads.append(t) for t in threads: t.join() c NaiveClient() # 若 n2000且服务端 fd 上限 1024峰值连接会撑爆 print(朴素客户端并发 2000 时服务端需承受约 2000 并发连接易超 fd 上限)真实场景里这 2000 并发连接会直接把服务端 fd 吃满。下面用连接池 限并发修复。五、解决方案第一层最小直接修复最小修复客户端用连接池复用 TCP 连接Semaphore限制并发 指数退避重试。import asyncio import httpx class PooledClient: 带连接池 并发限制 退避重试的客户端。 def __init__(self, base_url, max_concurrency64, max_connections64): self._sem asyncio.Semaphore(max_concurrency) # httpx.AsyncClient 内部维护连接池keep-alive 复用 self._client httpx.AsyncClient(base_urlbase_url, limitshttpx.Limits( max_connectionsmax_connections, max_keepalive_connectionsmax_connections), timeouthttpx.Timeout(60.0)) async def chat(self, payload, retries3): for attempt in range(retries): async with self._sem: # 限制并发 try: r await self._client.post(/v1/chat/completions, jsonpayload) r.raise_for_status() return r.json() except (httpx.ConnectError, httpx.TransportError) as e: if attempt retries - 1: raise # 指数退避避免重试风暴 await asyncio.sleep(0.5 * (2 ** attempt)) async def run_pooled(base_url, n): client PooledClient(base_url, max_concurrency64) tasks [client.chat({model: x, messages: []}) for _ in range(n)] # 并发被信号量限到 64连接池复用fd 稳定 return await asyncio.gather(*tasks, return_exceptionsTrue) # 用法 # asyncio.run(run_pooled(http://localhost:8000, 2000))这一层改动让客户端并发被限制、连接被复用服务端承受的并发连接数稳定在max_connections64而非 2000fd 不再耗尽。六、解决方案第二层结构化改进把服务端 fd / keep-alive 调优也做成结构化检测与配置两端配合客户端限并发 服务端提 fd 开 keep-alive。import resource import os def server_fd_guard(min_fd8192): 服务端启动期检测并尽量提高 fd 上限。 soft, hard resource.getrlimit(resource.RLIMIT_NOFILE) if soft min_fd: new_soft min(min_fd, hard) try: resource.setrlimit(resource.RLIMIT_NOFILE, (new_soft, hard)) except ValueError: print(f[warn] 无法提高到 {min_fd}当前软限 {soft}硬限 {hard}) cur_soft, _ resource.getrlimit(resource.RLIMIT_NOFILE) return cur_soft def report_uvicorn_tuning(): 给出 uvicorn 启动建议keep-alive 合理的 backlog。 return { keep_alive: 30, # 开 keep-alive复用连接 backlog: 2048, # 接受队列长度 # uvicorn 启动--limit-concurrency 按 GPU 数限制避免无限制接连接 limit_concurrency: 256, } # 用法服务端 main 入口最早调用 fd server_fd_guard(8192) print(服务端可用 fd 软限:, fd) print(uvicorn 建议:, report_uvicorn_tuning())server_fd_guard在服务端启动早期提高 fd 上限受系统硬限约束report_uvicorn_tuning给出 keep-alive 并发限制建议两端配合消掉高并发连接错误。七、解决方案第三层断言 / CI 守护并发连接错误最怕线上高并发才暴露。用断言守两条不变量def check_concurrency_invariants(base_url, n, max_conn): # 不变量 1客户端并发被信号量限制实际并发连接 max_conn # 用 httpx.Limits 保证连接池上限 client httpx.AsyncClient(base_urlbase_url, limitshttpx.Limits(max_connectionsmax_conn)) assert client._limits.max_connections max_conn # 不变量 2服务端 fd 软限必须 预期并发连接 soft, _ resource.getrlimit(resource.RLIMIT_NOFILE) assert soft max_conn, ffd 软限 {soft} 应 并发 {max_conn} return True def test_concurrency_safe(): import resource check_concurrency_invariants(http://x, 2000, max_conn64) print(OK: 并发连接不变量通过) if __name__ __main__: test_concurrency_safe()把test_concurrency_safe接进 CI用本地 mock server 或只做配置校验锁死客户端限并发 / 服务端 fd 足够。八、排查清单高并发打 vLLM API 报 Connection Error按序查看错误类型Too many open files→ fd 耗尽BrokenPipe→ 服务端在请求中途断了连接常因 fd 满后 accept 失败ConnectError/Timeout→ 连接建立被压垮或端口耗尽。客户端必须用连接池用requests.Session/httpx.AsyncClient内部 keep-alive千万不要每次请求新建 client。连接复用能把 fd 数降一个数量级。限制客户端并发用Semaphoreasyncio或线程池把并发控制在服务端能承受的范围如 64~256别无脑并发 2000。退避重试防风暴连接错误重试要用指数退避且限制重试次数避免失败→立刻重试→连接数翻倍的雪崩。服务端提 fd 上限ulimit -n 8192或写在启动脚本 / systemd 里server_fd_guard在启动期尽量提高软限。服务端开 keep-alive 限并发uvicorn 设--timeout-keep-alive 30复用连接必要时--limit-concurrency按 GPU 数限制避免无限制接连接把 fd 吃满。CI 接test_concurrency_safe校验客户端限并发 / 服务端 fd 足够高并发场景前先过这道闸。九、小结高并发打 vLLM API 报 Connection Error 的根因是连接资源fd / 连接数在高并发下被耗尽服务端 fd 上限过低 客户端不复用连接 无并发限制/重试风暴。三层修复第一层PooledClient用 httpx 连接池复用 TCP 连接 Semaphore限并发 指数退避重试把服务端承受的并发连接数稳定在池上限而非请求数第二层server_fd_guard服务端启动期提高 fd 软限report_uvicorn_tuning给出 keep-alive 并发限制建议两端配合第三层CI 断言守住客户端限并发 / 服务端 fd 足够高并发前先过闸。落实后vLLM API 在高并发下连接被复用、并发被限制、fd 足够不再因Too many open files/BrokenPipe拒绝连接。

相关新闻

sdm性能优化指南:提升Raspberry Pi镜像烧录速度的5个实用技巧

sdm性能优化指南:提升Raspberry Pi镜像烧录速度的5个实用技巧

sdm性能优化指南:提升Raspberry Pi镜像烧录速度的5个实用技巧 【免费下载链接】sdm Raspberry Pi SD Card Image Manager 项目地址: https://gitcode.com/gh_mirrors/sdm1/sdm sdm作为高效的Raspberry Pi SD卡镜像管理器,其烧录速度直接影响开发效…

2026/9/23 11:36:24 阅读更多 →
紧凑型设备中的红外测温方案: S-D1贴片传感器在IoT产品中的应用分析

紧凑型设备中的红外测温方案: S-D1贴片传感器在IoT产品中的应用分析

IoT设备小型化趋势下的测温挑战IoT设备的产品形态正在发生深刻变化——从工业级的大型网关到消费级的可穿戴设备、从固定安装的传感器节点到随身携带的智能终端,“更小、更薄、更省电”是贯穿其中的主旋律。这一趋势对温度传感器提出了一个核心矛盾:传统…

2026/9/19 9:05:48 阅读更多 →
Java面试进阶:从八股文到系统设计,掌握AI时代后端工程师核心能力

Java面试进阶:从八股文到系统设计,掌握AI时代后端工程师核心能力

1. 先搞清楚现在面试到底在考什么,别盲目背题 如果你现在还在用三年前的套路准备Java面试,大概率会碰壁。现在的面试,尤其是面对AI工具普及和降本增效的大环境,已经不再是单纯问你“HashMap原理”或者背出“Spring Bean生命周期”就能过关了。面试官更看重的是 你能否把技…

2026/9/21 3:51:48 阅读更多 →

最新新闻

STM32培训避坑指南:从硬件语义到量产能力的四层验证法

STM32培训避坑指南:从硬件语义到量产能力的四层验证法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:37:09 阅读更多 →
Android system.img解包与权限管理深度解析

Android system.img解包与权限管理深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:37:09 阅读更多 →
自托管CRM系统DeskcommCRM部署与配置实战指南

自托管CRM系统DeskcommCRM部署与配置实战指南

1. 先说清楚:DeskcommCRM 是什么,解决什么问题做 CRM 这一行,我前后接触过不少产品。Salesforce 功能全但配置太重,本土 SaaS 用起来方便但数据在别人手里,定制需求一多就处处受制。所以当时看到 DeskcommCRM 这个自托…

2026/9/25 6:37:09 阅读更多 →
OpenART Plus与AprilTag实战:智能车视觉定位与AR引导线实现

OpenART Plus与AprilTag实战:智能车视觉定位与AR引导线实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:37:09 阅读更多 →
通信原理课后题手推手画手验:从PDF答案到MATLAB/GNU Radio闭环验证

通信原理课后题手推手画手验:从PDF答案到MATLAB/GNU Radio闭环验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:37:09 阅读更多 →
Mac上录制系统声音和画外音:从Soundflower到Blackhole的迁移指南

Mac上录制系统声音和画外音:从Soundflower到Blackhole的迁移指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 6:36:08 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →