Prhub

#26576 [EPD] feat: encoder DP mode with per-rank subprocess workers

原始 PR 作者 Abatom 合并时间 2026-06-04 12:37 文件变更 2 提交数 11 评论 39 代码增减 +915 / -2

执行摘要

编码器服务器新增 per-rank 子进程数据并行模式

当前解耦编码器服务器在同一进程中运行单个 MMEncoder 和 FastAPI 应用,GPU 工作阻塞事件循环,且每个实例只能利用一个 GPU。此 PR 通过添加 per-rank 子进程数据并行模式解决该问题,使得路由进程保持空闲,GPU 工作并行化。

建议精读。该 PR 引入了复杂的进程间通信和生命周期管理,设计决策(如 ZMQ IPC、worker watchdog、背压控制)值得学习。对于生产部署,建议添加集成测试覆盖故障场景。

讨论亮点
  • 僵尸进程风险:gemini-code-assist 指出 _result_listener 在 30 次连续错误后退出会导致永久僵尸状态,建议改为无限重试加退避。作者已修复。
  • GPU 隔离方式:ShangmingCai 认为通过覆盖 CUDA_VISIBLE_DEVICES 环境变量危险。作者改用 maybe_reindex_device_id(gpu_id) 上下文管理器,与引擎其他组件一致。
  • 健康检查严格性:ShangmingCai 和 ZhengWG 推动健康检查应反映 worker 存活状态。最终实现 all_ranks_alive 检查,任何死 rank 返回 503。
  • TP+DP 支持:ZhengWG 询问能否同时使用 TP>1 和 DP。作者解释当前限制,计划后续 PR 支持。

实现拆解

  1. 环境变量environ.py 新增 SGLANG_ENCODER_DP_WORKER_MAX_INFLIGHT(默认 64),控制每个 worker 的最大并发请求数。
  2. DPDispatcher 类encode_server.py 新增路由中心,维护 pending_countsalive_ranks_dead_ranks,暴露 dispatchdispatch_sendbroadcast 方法,采用 least-pending + round-robin 选择 rank。
  3. Worker 进程启动_launch_server_dp 函数检测 dp_size > 1,通过 multiprocessing.Process 启动子进程,使用 maybe_reindex_device_id 隔离 GPU。
  4. 子进程运行逻辑run_dp_worker 内含独立 MMEncoder 和 EncoderScheduler,通过 ZMQ PUSH/PULL 与主进程通信,使用 asyncio.Semaphore 限流。
  5. 路由适配:修改 /encode/send/health_generate/start_profile/stop_profile 等端点,在 DP 活跃时委托给 DPDispatcher,正确传递 HTTP 状态码。
  6. 健康检查与错误处理ResultListener 循环监听 worker 结果;watchdog 检测进程退出并标记死 rank;超时机制避免请求无限等待。
    注意:本次 PR 没有包含新增的测试文件。
文件 模块 状态 重要度
python/sglang/srt/disaggregation/encode_server.py 编码器 modified 8.84
python/sglang/srt/environ.py 配置项 modified 3.95

关键符号

DPDispatcher DPDispatcher.__init__ DPDispatcher.dispatch DPDispatcher.dispatch_send DPDispatcher.broadcast _launch_server_dp run_dp_worker _dp_worker_encode_and_send _dp_worker_health_encode _push_embedding_to_prefill

关键源码片段

python/sglang/srt/disaggregation/encode_server.py core-logic

实现编码器数据并行模式的核心文件,包含 DPDispatcher、worker 启动、请求路由等全部逻辑

async def _push_embedding_to_prefill(enc: MMEncoder, request: dict) -> None:
    """
    将编码后的 embedding 推送到 prefill 阶段。
    对于 mooncake 后端为 no-op(transfer 由独立的 /send 处理)。
    embedding_port=None 会在上游被拒绝,因此此处 ports 必然存在。
    """
    req_id = request["req_id"]
    backend = enc.server_args.encoder_transfer_backend
​
    # zmq_to_tokenizer:单个 embedding_port,直接 send 后清理
    if backend == "zmq_to_tokenizer":
        await enc.send(
            req_id=req_id,
            prefill_host=request["prefill_host"],
            embedding_port=request["embedding_port"],
        )
        enc.embedding_to_send.pop(req_id, None)
        return
​
    # zmq_to_scheduler:多个 embedding_port(list),并发 send
    if backend == "zmq_to_scheduler":
        ports = request["embedding_port"]
        assert isinstance(ports, list)
        await asyncio.gather(
            *(
                enc.send(
                    req_id=req_id,
                    prefill_host=request["prefill_host"],
                    embedding_port=p,
                )
                for p in ports
            )
        )
        enc.embedding_to_send.pop(req_id, None)

评论区精华

_result_listener 退出条件导致僵尸状态 正确性

gemini-code-assist 指出 30 次连续错误后静默退出会使调度器处于永久僵尸状态,所有请求将超时。建议移除退出条件,改为带退避的重试。

结论:作者移除退出条件,并添加退避重试(commit 可见)。 · 已解决

CUDA_VISIBLE_DEVICES 覆盖危险 设计

ShangmingCai 认为覆盖环境变量危险,建议子进程内设置。

结论:作者改用 maybe_reindex_device_id(gpu_id) 上下文管理器,保持父进程设置,与引擎现有模式一致。 · 已解决

健康检查逻辑改进 正确性

ShangmingCai 指出健康检查应检查死 rank,不应总是 200。ZhengWG 建议执行虚拟编码探测。

结论:作者实现 all_ranks_alive 检查,任何死 rank 返回 503。 · 已解决

TP+DP 支持 设计

ZhengWG 询问能否同时使用 TP>1 和 DP。作者解释当前限制(每个 worker 需要成为 TP group leader,涉及 NCCL 独立初始化等),计划后续 PR。

结论:暂不支持 tp_size>1,作者将作为后续 PR。 · 待处理

风险与影响

具体风险:

  • 子进程泄漏:主进程异常退出可能留下孤儿进程,虽注册 atexit 但无法覆盖 SIGKILL。建议配合进程管理器。
  • ZMQ 通信可靠性:worker 崩溃导致请求超时;ResultListener 退避重试减轻瞬态故障。
  • 全局状态一致性dp_dispatcher 是模块级变量,非线程安全,但当前单线程事件循环风险低。
  • 配置冲突:dp_size > 1 要求 tp_size == 1,不符合时直接报错,用户需明确感知。

对用户:启用 --dp-size > 1 后,编码器吞吐量可随 GPU 数量线性扩展,但对小型模型可能增加延迟。
对系统:增加子进程数量,消耗额外 GPU 内存和 CPU 资源。
对团队:维护风险和复杂性增加,但功能齐全,为后续 TP+DP 打好基础。

子进程管理风险 ZMQ 通信健壮性 全局状态一致性 配置冲突风险

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论