执行摘要
- 一句话:修复PD解聚模式下follow_bootstrap_room负载均衡策略与外部路由指定DP rank冲突的bug。
- 推荐动作:该PR值得精读,特别是对于涉及PD解聚、数据并行和负载均衡策略的开发者。关注
CommonKVSender.__init__中的冲突检测逻辑和_resolve_prefill_dp_rank中的条件调整,这些设计决策平衡了性能与正确性。同时,环境变量的引入展示了如何为复杂部署场景提供逃生舱口。
功能与动机
PR body明确指出,在PD解聚模式下,解码服务器需要知道处理特定请求的预填充DP worker,以建立正确的KV传输连接。当预填充负载均衡方法为follow_bootstrap_room时,系统假设预填充DP rank始终为bootstrap_room % dp_size,并跳过向引导服务器注册rank的步骤。然而,如果外部路由器通过routed_dp_rank覆盖了此策略,预填充不会注册实际rank,而解码端仍会错误推断rank,导致连接不匹配。
实现拆解
- 预填充端冲突检测(
python/sglang/srt/disaggregation/common/conn.py):在CommonKVSender.__init__中,当负载均衡方法为follow_bootstrap_room且dp_size > 1时,检查实际attn_dp_rank是否等于bootstrap_room % dp_size。若不相等(表明被外部routed_dp_rank覆盖),则根据环境变量SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK决定:若启用则注册rank;否则记录失败并中止请求,提供清晰的错误信息。
- 解码端快速路径条件调整(
python/sglang/srt/disaggregation/decode.py):在_resolve_prefill_dp_rank中,当prefill_info.follow_bootstrap_room为真时,增加环境变量检查。仅当SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK未启用时,才返回bootstrap_room % dp_size作为快速路径,否则返回None以触发查询。
- 新增环境变量(
python/sglang/srt/environ.py):添加SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK(默认False),作为逃生舱口,允许在混合路由场景下强制查询预填充DP rank,但会增加HTTP往返开销。
- 测试与文档配套:PR body的检查清单显示单元测试和文档更新待完成,但提交历史和review中未提供具体变更。
关键文件:
python/sglang/srt/disaggregation/common/conn.py(模块 解聚模块;类别 source;类型 core-logic;符号 CommonKVSender.init): 预填充端KV发送器的初始化逻辑,负责检测follow_bootstrap_room策略与外部路由的冲突,是修复的核心文件。
python/sglang/srt/disaggregation/decode.py(模块 解聚模块;类别 source;类型 core-logic;符号 _resolve_prefill_dp_rank): 解码端DP rank解析逻辑,调整快速路径条件以支持环境变量覆盖,确保与预填充端行为一致。
python/sglang/srt/environ.py(模块 核心配置;类别 source;类型 configuration;符号 SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK): 新增环境变量SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK,作为混合路由场景的配置逃生舱口。
关键符号:CommonKVSender.init, _resolve_prefill_dp_rank
关键源码片段
python/sglang/srt/disaggregation/common/conn.py
预填充端KV发送器的初始化逻辑,负责检测follow_bootstrap_room策略与外部路由的冲突,是修复的核心文件。
class CommonKVSender(BaseKVSender):
def __init__(
self,
mgr: CommonKVManager,
bootstrap_addr: str,
bootstrap_room: int,
dest_tp_ranks: List[int],
pp_rank: int,
):
# ... 初始化基础属性 ...
self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Bootstrapping)
if self.kv_mgr.server_args.dp_size > 1:
if self.kv_mgr.server_args.load_balance_method != "follow_bootstrap_room":
# 非follow_bootstrap_room策略,正常注册DP rank
self._register_prefill_dp_rank()
elif (
self.kv_mgr.attn_dp_rank
!= self.bootstrap_room % self.kv_mgr.server_args.dp_size
):
# 检测到冲突:follow_bootstrap_room策略被外部routed_dp_rank覆盖
if envs.SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK.get():
# 启用逃生舱口,强制注册实际rank以供查询
self._register_prefill_dp_rank()
else:
# 默认行为:记录失败并中止请求,避免解码端错误推断
self.kv_mgr.record_failure(
self.bootstrap_room,
f"follow_bootstrap_room conflict: dispatched to dp_rank "
f"{self.kv_mgr.attn_dp_rank} but bootstrap_room "
f"{self.bootstrap_room} implies dp_rank "
f"{self.bootstrap_room % self.kv_mgr.server_args.dp_size}. "
f"Set SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK=1 "
f"to allow mixed routing.",
)
self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Failed)
return # 中止初始化,请求失败
# 若无冲突,follow_bootstrap_room策略保持快速路径,不注册rank
python/sglang/srt/disaggregation/decode.py
解码端DP rank解析逻辑,调整快速路径条件以支持环境变量覆盖,确保与预填充端行为一致。
def _resolve_prefill_dp_rank(self, req: Req) -> Optional[int]:
if req.disagg_prefill_dp_rank is not None:
return req.disagg_prefill_dp_rank # 优先使用请求中显式传递的rank
prefill_info = self.kv_manager.prefill_info_table.get(_bootstrap_addr(req))
if prefill_info is None:
return None # 无预填充信息,需查询
if prefill_info.dp_size == 1:
return 0 # 单DP rank场景
if (
prefill_info.follow_bootstrap_room
and not envs.SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK.get()
):
# 快速路径:仅当follow_bootstrap_room启用且未强制查询时,推断rank
return req.bootstrap_room % prefill_info.dp_size
return None # 触发查询实际rank
评论区精华
Reviewer ShangmingCai指出,移除快速路径会增加TTFT(首令牌时间),并建议检查是否由路由器分配了DP rank来决定是否绕过注册和查询。作者ByronHsu和hnyls2002在Issue评论中进一步讨论:hnyls2002认为follow_bootstrap_room是严格策略,但routed_dp_rank会静默覆盖,理想解决方案是路由器传递disagg_prefill_dp_rank。ByronHsu提议禁止在follow_bootstrap_room中使用显式DP rank,用户可选择其他策略。最终实现采纳了冲突检测和优雅失败的折中方案,保留了快速路径并添加环境变量逃生舱口。
- follow_bootstrap_room快速路径与外部路由冲突的处理策略 (design): 采用冲突检测和优雅失败的折中方案,保留快速路径,添加环境变量逃生舱口,以平衡性能与正确性。
风险与影响
- 风险:1. 回归风险:对于严格使用follow_bootstrap_room且无外部路由覆盖的场景,快速路径保留,无性能回归。但对于冲突场景,请求会被中止,可能导致服务中断,需用户调整配置或启用环境变量。
2. 性能风险:启用SGLANG_DISAGGREGATION_FORCE_QUERY_PREFILL_DP_RANK时,每个请求增加一次HTTP注册/查询调用,可能影响TTFT和吞吐量。
3. 兼容性风险:变更引入了新的环境变量和错误处理逻辑,可能影响现有部署的监控和故障排查流程。
4. 测试覆盖不足:PR body检查清单显示单元测试待添加,当前提交未包含测试文件变更,可能遗漏边缘情况验证。
- 影响:1. 用户影响:使用PD解聚模式且混合follow_bootstrap_room与外部路由的用户,之前会静默失败,现在会收到明确错误,指导他们调整配置或启用环境变量。这提高了系统的可观测性和健壮性。
2. 系统影响:修复了KV传输连接错误的核心bug,确保数据并行场景下解聚模式的正确性。对性能影响可控,保留了常见场景的优化路径。
3. 团队影响:引入了更精细的冲突处理机制和环境变量配置,为未来类似路由策略集成提供了模式参考。
- 风险标记:核心路径变更, 缺少测试覆盖, 配置依赖风险
关联脉络
- PR #22758 [sgl] provide an option to send control req to all dp ranks rank0: 同样涉及数据并行(DP)模式下的请求路由和优化,关注DP rank分配和通信开销。
- PR #22920 Remove compatibility restriction between Pipeline Parallelism and Mixed Chunked Prefill: 涉及并行策略的兼容性调整,与本PR在负载均衡和策略冲突处理上有相似主题。
参与讨论