执行摘要
- 一句话:健康检查失败时触发调度器 py-spy 与 CUDA coredump 诊断
- 推荐动作:建议所有涉及服务可靠性的团队阅读此 PR,尤其是
dump_requests_before_crash 和 _handle_crash_dump_env 的逻辑。其模块化设计和环境变量门控策略值得借鉴。
功能与动机
在健康检查失败时,现有的诊断信息覆盖了整个进程,不够聚焦于 scheduler/TP worker 进程。该 PR 旨在将诊断范围精确限定到 scheduler 进程,并支持独立开关,便于线上问题定位而无需改代码。
实现拆解
- 新增诊断工具模块:在
utils/cudacore_pyspy_dump_utils.py 中实现核心函数:collect_scheduler_processes 通过 psutil 遍历子进程并筛选出以 sglang::scheduler 开头的进程;pyspy_dump_schedulers 对筛选出的进程执行 py-spy dump(含 --native 回退);trigger_cuda_user_coredump 向 CUDA coredump 管道写入触发信号;_resolve_cuda_coredump_pipe_path 解析管道路径。
- 改造 crash dump 流程:在
tokenizer_manager.py 的 dump_requests_before_crash 方法中,新增两个环境变量 SGLANG_PYSPY_DUMP_BEFORE_CRASH 和 SGLANG_CUDA_COREDUMP_BEFORE_CRASH 作为进入诊断分支的新条件。当诊断启用时,先调用 pyspy_dump_schedulers(scheduler_only=True) 和 trigger_cuda_user_coredump(scheduler_only=True),再执行原有的请求信息转储。还引入了 SGLANG_CUDA_COREDUMP_BEFORE_CRASH_WAIT_SECS 作为等待延迟。
- 环境变量声明:在
environ.py 中注册上述三个新环境变量,默认值均为 True(等待秒数默认 60.0)。
- 自动设置 CUDA coredump 环境:在
server_args.py 新增 _handle_crash_dump_env 方法,在 __post_init__ 中调用。若用户设置了 --crash-dump-folder,自动注入 CUDA_ENABLE_COREDUMP_ON_EXCEPTION、CUDA_ENABLE_USER_TRIGGERED_COREDUMP 等环境变量,并创建以 hostname 命名的子目录。
- 代码清理与导入更新:将原来位于
utils/common.py 的旧版 pyspy_dump_schedulers 删除;将 watchdog.py 中的导入路径指向新模块。
关键文件:
python/sglang/srt/utils/cudacore_pyspy_dump_utils.py(模块 诊断工具;类别 source;类型 new-module;符号 _resolve_cuda_coredump_pipe_path, _is_sglang_scheduler_process, collect_scheduler_processes, pyspy_dump_schedulers): 新增文件,包含所有诊断核心逻辑:进程收集、py-spy dump、CUDA coredump 触发。
python/sglang/srt/managers/tokenizer_manager.py(模块 分词管理器;类别 source;类型 dependency-wiring;符号 dump_requests_before_crash): 核心入口,在健康检查失败的 dump_requests_before_crash 方法中集成了 py-spy dump 和 CUDA coredump。
python/sglang/srt/server_args.py(模块 服务参数;类别 source;类型 core-logic;符号 _handle_crash_dump_env): 新增 _handle_crash_dump_env 方法,当设置 --crash-dump-folder 时自动配置 CUDA coredump 环境变量并创建目录。
python/sglang/srt/environ.py(模块 环境变量;类别 source;类型 configuration): 声明三个新环境变量,作为诊断功能的全局开关。
python/sglang/srt/utils/common.py(模块 通用工具;类别 source;类型 refactor;符号 pyspy_dump_schedulers): 删除了原有的 pyspy_dump_schedulers 函数,功能完整迁移至新模块。
python/sglang/srt/utils/watchdog.py(模块 看门狗;类别 source;类型 dependency-wiring): 更新导入路径,指向新的诊断模块。
关键符号:_resolve_cuda_coredump_pipe_path, _is_sglang_scheduler_process, collect_scheduler_processes, pyspy_dump_schedulers, trigger_cuda_user_coredump, _handle_crash_dump_env, dump_requests_before_crash
关键源码片段
python/sglang/srt/managers/tokenizer_manager.py
核心入口,在健康检查失败的 dump_requests_before_crash 方法中集成了 py-spy dump 和 CUDA coredump。
def dump_requests_before_crash(
self,
hostname: str = os.getenv("HOSTNAME", socket.gethostname()),
):
"""在进程崩溃前执行诊断:py-spy dump 和 CUDA coredump,然后 dump 请求信息。"""
# 读取诊断开关环境变量(均在 environ.py 中声明,默认 True)
should_dump_pyspy = envs.SGLANG_PYSPY_DUMP_BEFORE_CRASH.get()
should_dump_cuda_coredump = envs.SGLANG_CUDA_COREDUMP_BEFORE_CRASH.get()
should_dump_diagnostics = should_dump_pyspy or should_dump_cuda_coredump
# 如果既没有设置 crash_dump_folder,也没有启用诊断,则直接返回
if not self.crash_dump_folder and not should_dump_diagnostics:
return
if self.crash_dump_performed:
return
else:
self.crash_dump_performed = True
# 先执行 py-spy dump(仅 scheduler 进程)
if should_dump_pyspy:
# 使用精确的 scheduler_only=True,只 dump scheduler 进程
pyspy_dump_schedulers(scheduler_only=True)
# 再触发 CUDA coredump(仅 scheduler 进程)
if should_dump_cuda_coredump:
# 等待一小段时间让 py-spy 完成,避免同时操作影响
time.sleep(envs.SGLANG_CUDA_COREDUMP_BEFORE_CRASH_WAIT_SECS.get())
trigger_cuda_user_coredump(scheduler_only=True)
# 接着执行原有的请求信息转储逻辑
if self.crash_dump_folder:
logger.error(f"Dumping requests before crash. {self.crash_dump_folder=}")
# ... 原有请求 dump 代码
python/sglang/srt/server_args.py
新增 _handle_crash_dump_env 方法,当设置 --crash-dump-folder 时自动配置 CUDA coredump 环境变量并创建目录。
def _handle_crash_dump_env(self):
"""当设置了 crash_dump_folder 时,自动注入 CUDA coredump 环境变量"""
if not self.crash_dump_folder:
return
# 默认 CUDA coredump 配置(除非用户已在环境中显式设置)
_CUDA_COREDUMP_DEFAULTS = {
"CUDA_ENABLE_COREDUMP_ON_EXCEPTION": "1",
"CUDA_ENABLE_USER_TRIGGERED_COREDUMP": "1",
"CUDA_COREDUMP_SHOW_PROGRESS": "1",
"CUDA_COREDUMP_GENERATION_FLAGS": (
"skip_nonrelocated_elf_images,skip_global_memory,"
"skip_shared_memory,skip_local_memory,skip_constbank_memory"
),
"CUDA_COREDUMP_FILE": f"{self.crash_dump_folder}/%h/core.cuda.%t.%p",
"CUDA_COREDUMP_PIPE": "/tmp/corepipe.cuda.%h.%p",
}
for key, value in _CUDA_COREDUMP_DEFAULTS.items():
if key not in os.environ:
os.environ[key] = value
logger.info("Auto-set %s=%s (from --crash-dump-folder)", key, value)
if key == "CUDA_COREDUMP_FILE":
# CUDA coredump 要求目标目录存在,预先创建以 hostname 命名的子目录
hostname = socket.gethostname()
os.makedirs(
os.path.join(self.crash_dump_folder, hostname),
exist_ok=True,
)
评论区精华
该 PR 无实质性 review 讨论,仅涉及操作评论(merrymercy 通过 /rerun-test 触发回归测试)。设计决策隐含在 commit 和代码中。
- 测试验证方式 (testing): 测试通过,PR 被合并。
风险与影响
- 风险:
- 磁盘占用风险:CUDA coredump 文件较大(测试中单文件 255MB),若健康检查频繁失败可能快速占满磁盘。建议在生产环境按需启用
SGLANG_CUDA_COREDUMP_BEFORE_CRASH=0。
- 默认启用影响:所有用户默认会开启这两个诊断,可能对性能敏感场景有轻微影响(py-spy 会暂停进程数百毫秒)。可通过环境变量关闭。
- 仅支持 Linux:CUDA coredump 机制及
psutil 进程遍历依赖 Linux 特定特性,在其他平台可能降级或报错。
- 环境变量冲突:若用户未设置
CUDA_ENABLE_USER_TRIGGERED_COREDUMP 但通过 --crash-dump-folder 自动注入,可能覆盖用户的显式配置。
- 影响:影响范围中等:仅当健康检查返回 503 时触发,正常请求无影响。对启用诊断的用户,可获得更精确的 scheduler 级别堆栈和 GPU 状态,极大加速问题排查。诊断默认开启,但可通过环境变量关闭,不影响现有行为。代码重构将相关函数独立为模块,提高了可维护性。
- 风险标记:CUDA coredump 可能产生大文件, 诊断默认开启,可能影响性能, 仅 Linux 平台支持, 环境变量自动注入可能覆盖用户配置
关联脉络
- PR #27428 [debug] Register #27338 EAGLE draft kv_indices revert in pr_fix_toggle: 同样属于调试诊断工具链的增强,与本 PR 共同构成了 SGLang 的可观测性与调试基础设施。
参与讨论