Prhub

#7412 [PD Disaggregation] Enable PD deployment without Router

PaddlePaddle/FastDeploy · 作者 juncaipeng · 合并时间 2026-04-15 20:13

分析状态 已生成
文件变更 6提交数 1 · 评论 10
代码增减 +472 / -126
Feature Scheduler Engine test

执行摘要

支持 PD 分离部署无需路由器,放宽配置限制并新增测试验证。

根据PR body,动机是'对齐RL使用场景,PD分离部署不强制依赖router。' 这意味着为了满足强化学习场景的需求,需要支持无需路由器的PD分离部署,以降低部署复杂度和适应特定使用场景。

该PR值得精读,特别是配置松耦合的设计决策(如init_pd_info逻辑调整)和测试模拟无路由器部署的方法。建议关注并发处理优化和兼容性权衡,以指导类似部署场景的实现。

讨论亮点

Review中主要讨论点:1. 兼容性风险:Copilot指出args_utils.py中禁止scheduler_name=="splitwise"可能影响v0部署兼容性,建议明确处理或更新文档。2. 方法重命名遗漏调用:Copilot警告init_cache_info重命名为init_pd_info后,其他调用点(如expert_service.py)需同步更新,否则可能导致运行时错误。3. 测试并发逻辑缺陷:Copilot指出测试中_send_pd_request使用ThreadPoolExecutor可能阻塞,未真正实现非阻塞fan-out行为,建议优化。4. 测试覆盖不足:fastdeploy-bot建议补充其他传输协议(如IPC)的测试用例,确保无路由器场景下所有协议正常工作。

实现拆解

  1. 新增端到端测试文件:在tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py中新增测试,模拟无路由器时手动构建disaggregate_info并并发向Prefill和Decode发送请求,验证RDMA传输协议。关键符号包括_build_disaggregate_info_send_pd_request
  2. 重命名配置初始化方法:在fastdeploy/config.py中,将init_cache_info方法重命名为init_pd_info,并调整逻辑,使local调度器不再强制要求路由器,从而支持无路由器部署。这影响后续调度器初始化。
  3. 调整参数校验逻辑:在fastdeploy/engine/args_utils.py中,修改__post_init__方法:当scheduler_name"splitwise"时抛出错误(可能推动v0部署废弃),当scheduler_name"local"routerNone时从错误改为警告,允许运行。
  4. 删除废弃脚本:删除examples/splitwise/start_v0_tp1.sh脚本,可能因v0部署不再支持或整合到新逻辑中。
  5. 更新其他调用点:在fastdeploy/engine/expert_service.pytests/model_executor/test_thinking_budget.py中,将init_cache_info调用更新为init_pd_info,确保一致性。
文件 模块 状态 重要度
tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py PD 分离测试 added 8.45
fastdeploy/config.py 配置管理 modified 5.31
fastdeploy/engine/args_utils.py 参数校验 modified 4.44
examples/splitwise/start_v0_tp1.sh 示例脚本 removed 4.79
tests/model_executor/test_thinking_budget.py 思考预算测试 modified 3.46
fastdeploy/engine/expert_service.py 专家服务 modified 3.17
tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py test-coverage

新增端到端测试,验证无路由器 PD 部署的完整流程,是关键验证手段。

def _build_disaggregate_info() -> dict:
    """
    手动构建disaggregate_info,模拟Router的handle_splitwise_request逻辑。
    用于无路由器场景下,提供Prefill和Decode节点的连接信息。
    """
    host_ip = os.getenv("FD_HOST_IP", "127.0.0.1")
    return {
        "prefill_ip": host_ip, # Prefill节点的IP地址
        "decode_ip": host_ip, # Decode节点的IP地址
        "prefill_connector_port": FD_CONNECTOR_PORT, # Prefill连接器端口
        "decode_connector_port": FD_CONNECTOR_PORT + 1, # Decode连接器端口
        "decode_device_ids": ["1"], # Decode设备ID列表
        "decode_rdma_ports": [FD_RDMA_PORT + 1], # Decode RDMA端口列表
        "transfer_protocol": "rdma", # 传输协议设置为RDMA
        "decode_tp_size": 1, # Decode TP大小
    }
fastdeploy/config.py infrastructure

修改配置初始化逻辑,重命名方法并调整 splitwise_version 判断,是支持无路由器部署的核心。

def init_pd_info(self):
    """
    初始化PD部署信息,支持无路由器场景。
    根据调度器名称确定splitwise版本:v0用于splitwise或dp调度器,v1用于local调度器(路由器可选)。
    """
    # TODO: 分组splitwise参数
    # PD分离部署有两种方法:
    # 1. v0: 使用splitwise_scheduler或dp_scheduler
    # 2. v1: 使用local_scheduler + router(可选)
    self.splitwise_version = None
    if self.scheduler_config.name in ("splitwise", "dp"):
        self.splitwise_version = "v0" # v0版本,依赖splitwise调度器
    elif self.scheduler_config.name == "local":
        self.splitwise_version = "v1" # v1版本,local调度器支持无路由器
fastdeploy/engine/args_utils.py infrastructure

调整参数校验,允许 local 调度器无路由器运行,并禁止 splitwise 调度器以推动 v0 废弃。

if self.splitwise_role != "mixed":
    if self.scheduler_name == "splitwise":
        # 禁止使用splitwise调度器,推动v0部署废弃
        raise ValueError(
            "Setting scheduler_name as splitwise is not supported in pd deployment, "
            "please use router as scheduler."
        )
    if self.scheduler_name == "local" and self.router is None:
        # 允许local调度器无路由器运行,改为警告提示
        console_logger.warning(
            f"Running {self.splitwise_role} role with {self.scheduler_name} "
            f"scheduler without --router. Router registration and request routing will be disabled."
        )

关键符号

init_pd_info _build_disaggregate_info _send_pd_request __post_init__

评论区精华

兼容性风险:禁止 splitwise 调度器 设计

Copilot 指出禁止 scheduler_name=="splitwise" 可能影响 v0 部署兼容性,建议明确处理或更新文档。

结论:未在 PR 中明确解决,可能需后续评估或提供迁移指引。 · unresolved

方法重命名遗漏调用 正确性

Copilot 警告 init_cache_info 重命名后调用点未同步更新,可能导致运行时 AttributeError。

结论:PR 中已更新 expert_service.py 和测试文件,但可能仍有遗漏调用点,风险部分缓解。 · partially resolved

测试并发逻辑缺陷 正确性

Copilot 指出测试中 ThreadPoolExecutor 可能阻塞,与预期 fan-out 行为不符,建议优化并发实现。

结论:未在 PR 中修改,测试逻辑可能存在阻塞问题,影响准确性。 · unresolved

测试覆盖不足 测试

fastdeploy-bot 建议补充其他传输协议(如 IPC)测试,确保无路由器场景下所有协议正常工作。

结论:仅测试 RDMA 协议,其他协议未覆盖,测试覆盖不全面。 · unresolved

风险与影响

技术风险包括:1. 方法重命名风险init_cache_info改为init_pd_info后,如果代码库中仍有未更新的调用点,会导致AttributeError,影响运行时稳定性。2. 并发逻辑缺陷:测试中_send_pd_request的并发实现可能阻塞,未模拟Router的fan-out行为,可能导致测试不准确或资源泄露。3. 兼容性风险:禁止scheduler_name=="splitwise"可能破坏现有v0部署,需评估影响并提供迁移路径。4. 测试覆盖不足:仅测试RDMA协议,其他传输协议未覆盖,可能隐藏无路由器场景下的潜在问题。

对用户的影响:PD分离部署现在可以不依赖路由器运行,降低了部署复杂度,尤其适用于RL等特定场景,提高了部署灵活性。对系统的影响:调度器和配置逻辑更松耦合,但需确保无路由器时的正确性和性能,可能增加配置复杂性。对团队的影响:需要更新相关文档和示例,并注意向后兼容性,团队在维护时需关注方法重命名和测试覆盖。

方法重命名遗漏调用 测试并发阻塞 兼容性风险 测试覆盖不足

关联 Issue

未识别关联 Issue

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

完整报告

执行摘要

  • 一句话:支持PD分离部署无需路由器,放宽配置限制并新增测试验证。
  • 推荐动作:该PR值得精读,特别是配置松耦合的设计决策(如init_pd_info逻辑调整)和测试模拟无路由器部署的方法。建议关注并发处理优化和兼容性权衡,以指导类似部署场景的实现。

功能与动机

根据PR body,动机是'对齐RL使用场景,PD分离部署不强制依赖router。' 这意味着为了满足强化学习场景的需求,需要支持无需路由器的PD分离部署,以降低部署复杂度和适应特定使用场景。

实现拆解

  1. 新增端到端测试文件:在tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py中新增测试,模拟无路由器时手动构建disaggregate_info并并发向Prefill和Decode发送请求,验证RDMA传输协议。关键符号包括_build_disaggregate_info_send_pd_request
  2. 重命名配置初始化方法:在fastdeploy/config.py中,将init_cache_info方法重命名为init_pd_info,并调整逻辑,使local调度器不再强制要求路由器,从而支持无路由器部署。这影响后续调度器初始化。
  3. 调整参数校验逻辑:在fastdeploy/engine/args_utils.py中,修改__post_init__方法:当scheduler_name"splitwise"时抛出错误(可能推动v0部署废弃),当scheduler_name"local"routerNone时从错误改为警告,允许运行。
  4. 删除废弃脚本:删除examples/splitwise/start_v0_tp1.sh脚本,可能因v0部署不再支持或整合到新逻辑中。
  5. 更新其他调用点:在fastdeploy/engine/expert_service.pytests/model_executor/test_thinking_budget.py中,将init_cache_info调用更新为init_pd_info,确保一致性。

关键文件:

  • tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py(模块 PD分离测试;类别 test;类型 test-coverage;符号 _build_disaggregate_info, _send_pd_request, _post_stream, _post): 新增端到端测试,验证无路由器PD部署的完整流程,是关键验证手段。
  • fastdeploy/config.py(模块 配置管理;类别 infra;类型 infrastructure;符号 init_cache_info, init_pd_info): 修改配置初始化逻辑,重命名方法并调整splitwise_version判断,是支持无路由器部署的核心。
  • fastdeploy/engine/args_utils.py(模块 参数校验;类别 infra;类型 infrastructure): 调整参数校验,允许local调度器无路由器运行,并禁止splitwise调度器以推动v0废弃。
  • examples/splitwise/start_v0_tp1.sh(模块 示例脚本;类别 other;类型 deletion): 删除废弃的v0部署脚本,可能因不再支持或整合到新逻辑中。
  • tests/model_executor/test_thinking_budget.py(模块 思考预算测试;类别 test;类型 test-coverage): 更新测试中的方法调用,确保与重命名后的init_pd_info一致。
  • fastdeploy/engine/expert_service.py(模块 专家服务;类别 infra;类型 infrastructure): 更新专家服务中的方法调用,确保配置初始化正确。

关键符号:init_pd_info, _build_disaggregate_info, _send_pd_request, post_init

关键源码片段

tests/e2e/test_ernie_03b_pd_wo_router_v1_rdma_tp1.py

新增端到端测试,验证无路由器PD部署的完整流程,是关键验证手段。

def _build_disaggregate_info() -> dict:
    """
    手动构建disaggregate_info,模拟Router的handle_splitwise_request逻辑。
    用于无路由器场景下,提供Prefill和Decode节点的连接信息。
    """
    host_ip = os.getenv("FD_HOST_IP", "127.0.0.1")
    return {
        "prefill_ip": host_ip, # Prefill节点的IP地址
        "decode_ip": host_ip, # Decode节点的IP地址
        "prefill_connector_port": FD_CONNECTOR_PORT, # Prefill连接器端口
        "decode_connector_port": FD_CONNECTOR_PORT + 1, # Decode连接器端口
        "decode_device_ids": ["1"], # Decode设备ID列表
        "decode_rdma_ports": [FD_RDMA_PORT + 1], # Decode RDMA端口列表
        "transfer_protocol": "rdma", # 传输协议设置为RDMA
        "decode_tp_size": 1, # Decode TP大小
    }

fastdeploy/config.py

修改配置初始化逻辑,重命名方法并调整splitwise_version判断,是支持无路由器部署的核心。

def init_pd_info(self):
    """
    初始化PD部署信息,支持无路由器场景。
    根据调度器名称确定splitwise版本:v0用于splitwise或dp调度器,v1用于local调度器(路由器可选)。
    """
    # TODO: 分组splitwise参数
    # PD分离部署有两种方法:
    # 1. v0: 使用splitwise_scheduler或dp_scheduler
    # 2. v1: 使用local_scheduler + router(可选)
    self.splitwise_version = None
    if self.scheduler_config.name in ("splitwise", "dp"):
        self.splitwise_version = "v0" # v0版本,依赖splitwise调度器
    elif self.scheduler_config.name == "local":
        self.splitwise_version = "v1" # v1版本,local调度器支持无路由器

fastdeploy/engine/args_utils.py

调整参数校验,允许local调度器无路由器运行,并禁止splitwise调度器以推动v0废弃。

if self.splitwise_role != "mixed":
    if self.scheduler_name == "splitwise":
        # 禁止使用splitwise调度器,推动v0部署废弃
        raise ValueError(
            "Setting scheduler_name as splitwise is not supported in pd deployment, "
            "please use router as scheduler."
        )
    if self.scheduler_name == "local" and self.router is None:
        # 允许local调度器无路由器运行,改为警告提示
        console_logger.warning(
            f"Running {self.splitwise_role} role with {self.scheduler_name} "
            f"scheduler without --router. Router registration and request routing will be disabled."
        )

评论区精华

Review中主要讨论点:1. 兼容性风险:Copilot指出args_utils.py中禁止scheduler_name=="splitwise"可能影响v0部署兼容性,建议明确处理或更新文档。2. 方法重命名遗漏调用:Copilot警告init_cache_info重命名为init_pd_info后,其他调用点(如expert_service.py)需同步更新,否则可能导致运行时错误。3. 测试并发逻辑缺陷:Copilot指出测试中_send_pd_request使用ThreadPoolExecutor可能阻塞,未真正实现非阻塞fan-out行为,建议优化。4. 测试覆盖不足:fastdeploy-bot建议补充其他传输协议(如IPC)的测试用例,确保无路由器场景下所有协议正常工作。

  • 兼容性风险:禁止splitwise调度器 (design): 未在PR中明确解决,可能需后续评估或提供迁移指引。
  • 方法重命名遗漏调用 (correctness): PR中已更新expert_service.py和测试文件,但可能仍有遗漏调用点,风险部分缓解。
  • 测试并发逻辑缺陷 (correctness): 未在PR中修改,测试逻辑可能存在阻塞问题,影响准确性。
  • 测试覆盖不足 (testing): 仅测试RDMA协议,其他协议未覆盖,测试覆盖不全面。

风险与影响

  • 风险:技术风险包括:1. 方法重命名风险init_cache_info改为init_pd_info后,如果代码库中仍有未更新的调用点,会导致AttributeError,影响运行时稳定性。2. 并发逻辑缺陷:测试中_send_pd_request的并发实现可能阻塞,未模拟Router的fan-out行为,可能导致测试不准确或资源泄露。3. 兼容性风险:禁止scheduler_name=="splitwise"可能破坏现有v0部署,需评估影响并提供迁移路径。4. 测试覆盖不足:仅测试RDMA协议,其他传输协议未覆盖,可能隐藏无路由器场景下的潜在问题。
  • 影响:对用户的影响:PD分离部署现在可以不依赖路由器运行,降低了部署复杂度,尤其适用于RL等特定场景,提高了部署灵活性。对系统的影响:调度器和配置逻辑更松耦合,但需确保无路由器时的正确性和性能,可能增加配置复杂性。对团队的影响:需要更新相关文档和示例,并注意向后兼容性,团队在维护时需关注方法重命名和测试覆盖。
  • 风险标记:方法重命名遗漏调用, 测试并发阻塞, 兼容性风险, 测试覆盖不足

关联脉络

  • PR #7364 [BugFix][PD Disaggregation][KVCache] Fix low cache hit rate in PD split (disaggregation) scenario: 同属PD分离部署场景,涉及调度器和缓存管理,与本PR的部署配置相关。
  • PR #7407 [BugFix][Scheduler]Fix FD_DISABLE_CHUNKED_PREFILL max_num_batched_tokens limit: 涉及调度器配置调整,与本PR的参数校验和调度器逻辑修改有间接关联。

参与讨论