Prhub

#34450 Raise PD zmq per-context socket cap via SGLANG_DISAGGREGATION_ZMQ_MAX_SOCKETS

原始 PR 作者 hanming-lu 合并时间 2026-08-12 06:27 文件变更 2 提交数 4 评论 1 代码增减 +7 / -0

执行摘要

新增 ZMQ 套接字上限配置,修复 PD 大规模连接失败

PR body 指出:Prefill ranks 可以耗尽 libzmq per-context socket cap(默认 1023),即使 OS 文件描述符限制足够。KV manager 为每个 decode endpoint 缓存一个 PUSH socket 和一个 PAIR monitor socket,因此 16 个 decode replicas × 32 DP ranks 需要 1025 个 sockets,transfer workers 在 connect 时开始失败。这是一个连接容量缓解措施。

建议运维和 disaggregation 相关开发阅读。该 PR 揭示了一个非直觉的规模瓶颈(libzmq per-context 上限而非 OS fd 上限),并以最小改动提供可调配置。值得关注的决策:默认值取 16384(约 16 倍默认值)并留在 Envs 中统一管理;同时作者明确承认 socket 缓存无界,后续 LRU eviction 是真正的根治方向,读者可跟踪该后续工作。

讨论亮点

PR 没有 review 评论。作者在 4 次提交中反复调整注释(从移除冗余注释到澄清动机),最终注释简洁说明“每个 decode endpoint 缓存 2 个 socket,大规模部署会超过默认上限”。Issue 评论仅有 /tag-and-rerun-ci 指令,无技术讨论。

实现拆解

1. 新增环境变量定义

python/sglang/srt/environ.pyEnvs 类中,于 PD disaggregation 配置段新增 SGLANG_DISAGGREGATION_ZMQ_MAX_SOCKETS = EnvInt(16384),默认值 16384(约 libzmq 默认上限 1023 的 16 倍),供所有组件通过 envs...get() 读取。

2. KVManager 初始化时提升 context 上限

python/sglang/srt/disaggregation/common/conn.py 的 KVManager 初始化方法中,创建 self._zmq_ctx = zmq.Context() 后立即调用 self._zmq_ctx.set(zmq.MAX_SOCKETS, envs.SGLANG_DISAGGREGATION_ZMQ_MAX_SOCKETS.get()),使该 context 内缓存的 PUSH/PAIR 套接字不受默认限制。

3. CommonKVReceiver 类级 context 同步设置

对共享的 CommonKVReceiver._ctx 类属性(zmq.Context())同样调用 _ctx.set(zmq.MAX_SOCKETS, ...),确保复用接收端套接字时也享有新上限。

4. 测试与文档

没有新增测试或文档(PR body 明确说明),作者仅验证了语法编译;注释在 4 个 commit 中逐步精简。

文件 模块 状态 重要度
python/sglang/srt/environ.py 环境配置 modified 4.35
python/sglang/srt/disaggregation/common/conn.py KV 传输 modified 5.42

关键符号

KVManager.__init__ CommonKVReceiver

关键源码片段

python/sglang/srt/disaggregation/common/conn.py core-logic

核心变更,两处应用 zmq.MAX_SOCKETS,解决大规模 PD 部署连接失败

# python/sglang/srt/disaggregation/common/conn.pyclass KVManager:
    def __init__(self, ...):
        ...
        # bind zmq socket
        self._zmq_ctx = zmq.Context()
        # 将 per-context 套接字上限从 libzmq 默认 1023 提升为可配置值,
        # 因为该 manager 为每个 decode endpoint 缓存 PUSH 与 PAIR monitor 两个 socket,
        # 大规模部署(如 16 decode × 32 DP)会超过默认上限,导致 transfer worker 连接失败。
        self._zmq_ctx.set(
            zmq.MAX_SOCKETS, envs.SGLANG_DISAGGREGATION_ZMQ_MAX_SOCKETS.get()
        )
        self.rank_port, self.server_socket = get_zmq_socket_on_host(
            self._zmq_ctx, zmq.PULL, host=self.local_ip
        )
        ...class CommonKVReceiver(BaseKVReceiver):
    _ctx = zmq.Context()
    # 共享接收端 context 同样应用新上限,保证所有复用 socket 不受 libzmq 默认 1023 约束
    _ctx.set(zmq.MAX_SOCKETS, envs.SGLANG_DISAGGREGATION_ZMQ_MAX_SOCKETS.get())
    _socket_cache = {}
    ...

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  • 文件描述符瓶颈转移:提升 ZMQ 上限后,OS 层面 ulimit -n 可能成为新的约束(ZMQ socket 底层也占用 fd),大规模部署仍需同步调高 fd 限制。
  • 内存增长:socket 缓存仍然无界,作者在 commit 中承认这是 minimal mitigation,后续需 LRU 驱逐来回收不活跃 socket。
  • 类级设置时机:CommonKVReceiver._ctx.set(...) 在类定义时执行,若 pyzmq 导入失败会在导入阶段直接报错;不过 conn.py 本就强依赖 zmq,风险低。
  • 缺少自动化测试:没有针对新环境变量的单元测试,但改动仅调整 context 选项,不改变消息语义,回归面小。
  • 用户侧:PD 大规模部署(如 16 decode × 32 DP)不再因 libzmq 默认 socket 上限发生连接失败,可用性提升。
  • 系统侧:ZMQ context 容量上限默认提高至 16384,内存占用与活跃连接数正相关;常规规模无感知。
  • 团队侧:新增 SGLANG 前缀环境变量(专家级配置),建议在 PD 部署文档中补充说明;当前 PR 未同步文档。
  • 影响范围:仅限 PD disaggregation 的 socket 创建路径(conn.py),不影响其他模块和模型输出。
socket 缓存无界 默认值依赖 OS fd 限制 缺少测试覆盖 类级 context 导入期设置

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论