[Bug][KV Offload][P2P] EngineCore crash reconnecting to peer: stale dead ZmqConnection remains registered

该报错发生在 vLLM 使用 OffloadingConnector P2P 辅助层且大量请求反复连接/断开同一对等节点(peer)时,因会话清理与传输层连接清理时序不一致,导致 ZmqConnection 仍注册在 _connections 中,触发断言 AssertionError: ZmqCo

快速结论:该报错发生在 vLLM 使用 OffloadingConnector P2P 辅助层且大量请求反复连接/断开同一对等节点(peer)时,因会话清理与传输层连接清理时序不一致,导致 ZmqConnection 仍注册在 _connections 中,触发断言 AssertionError: ZmqConnection to <peer>:7777 already exists,最终 EngineCore 崩溃。优先排查是否存在频繁的 peer 上下线,并检查 secondary_tiers 中是否启用了 P2P 类型。核心英文报错:[Bug][KV Offload][P2P] EngineCore crash reconnecting to peer: stale dead ZmqConnection remains registered

适用环境:vLLM 0.23.1rc1.dev1474+g0ba2aa35a(stock nightly 镜像);OffloadingConnector / TieringOffloadingSpecsecondary_tiers: [{"type": "p2p", ...}]--block-size 64;聚合部署,每个 pod 同时是 P2P 消费者和生产者。

最快修复方案:需对源码中 vllm/v1/kv_offload/tiering/p2p/control/zmq.py 进行以下修改(来自 Issue 中确认的修复 patch):

  1. 重连时仅注销已标记为 dead 的 ZmqConnection,保留对真正活跃连接的断言。
  2. _dead_closed 分离,使 mark_dead() 不再阻止 close() 释放 DEALER 和 monitor 套接字。
  3. monitor 端点改为连接级别唯一(如加入连接 ID),避免 EADDRINUSE 竞争。
  4. poll() 中先清理死亡连接再路由流量,防止轮询间被标记为 dead 的连接丢弃重连方的首条消息。

若无法自行修改代码,可尝试减少 peer 频繁重建(如增大会话超时、减少请求交替),但只能降低触发概率。

注意事项:该修复尚未合入 vLLM 主线(截至 Issue 关闭时),属于社区贡献的补丁。直接应用需确保版本匹配(针对维护分支或 nightly 构建)。跳过断言但不能修复底层套接字泄露会导致 EADDRINUSE 错误,因此必须完整应用上述四点修改。

问题场景

在 vLLM 部署中,启用 OffloadingConnector 的 P2P 辅助层(secondary_tiers: [{"type": "p2p"}]),并配置了共享前缀(shared-prefix)的持续负载,导致多个 peer 节点反复连接和断开。此时 EngineCoreon_new_request 中调用 _control.connect(peer_id) 时断言失败,进程崩溃。

报错原文

AssertionError: ZmqConnection to 10.0.8.45:7777 already exists
...
File "vllm/v1/kv_offload/tiering/p2p/control/zmq.py", line 131, in connect
  assert peer_id not in self._connections

原因分析

根本原因是 P2PSecondaryTierManager._poll_once() 中会话清理与传输层连接清理的时序不一致:

  • zmq.py 中的 poll() 先清理死亡连接(通过 _check_monitors()_recv_router()),随后 session.poll() 可能将 ControlConnection 标记为 dead;
  • 之后 _reap_dead_sessions() 根据 connected and not alive 移除会话,但已标记为 dead 的 ZmqConnection 仍保留在 zmq.py_connections 字典中;
  • 若在下一个 poll() 之前有 on_new_request() 请求该 peer,_get_or_create_session() 发现会话不存在,尝试 _control.connect(peer_id),但旧连接依然注册,触发断言。

进一步分析发现,即使绕过断言,ZmqConnection.mark_dead() 会将 _closed 设为 True,导致后续 close() 提前返回,无法释放 DEALER 和 monitor 套接字,进而引发 EADDRINUSE 错误。此外,monitor 端点基于 peer_id 生成,套接字释放后零拷贝线程仍可能持有该地址,造成竞争。

环境排查

celebrityanime
celebrityanime
文章: 15315

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注