执行摘要
- 一句话:防 race condition:flush_cache 增加 timeout 等待服务空闲
- 推荐动作:简单且聚焦的 bugfix,适合快速阅读。它展示了如何处理客户端与服务端之间的时序竞态,以及如何通过参数让服务端主动等待空闲。对 benchmark 使用者和 CI 维护者有价值。
功能与动机
PR body 中明确说明:Fix race condition where flush_server_cache gets HTTP 400 right after benchmark warmup. Client warmup gather complete does not guarantee the server scheduler is fully idle. Add timeout param to let server wait until is_fully_idle() passes before flushing cache. 也就是说,benchmark 脚本在 warmup 结束后立即调用 flush_cache,但服务端调度器可能还在处理残留状态,导致请求被拒绝,通过 timeout 参数让服务端等待空闲,从根源上解决时序竞态。
实现拆解
- 修改 python/sglang/benchmark/serving.py 中的 flush_server_cache 函数:原先直接 post 请求,现在针对非 vllm 后端(即 sglang 系列)构造 params={"timeout": 10.0},并作为 query 参数传给 /flush_cache 端点。vllm 后端对应 /reset_prefix_cache 不传 timeout。
- 同步更新 test/registered/bench_fn/test_benchmark_datasets_api.py 中的 test_embedding_cache_flush_uses_the_engine_specific_endpoint 单元测试,断言 vllm 调用时 params 为空字典,sglang 调用时 params 为 {"timeout": 10.0},确保新行为的回归覆盖。
- 该改动只影响 benchmark 脚本的缓存清理路径,不涉及推理运行时逻辑,风险面小。
关键文件:
python/sglang/benchmark/serving.py(模块 基准脚本;类别 source;类型 core-logic;符号 flush_server_cache): 核心修改文件,flush_server_cache 函数增加 timeout 参数,解决 warmup 后 flush_cache 的竞态失败。
test/registered/bench_fn/test_benchmark_datasets_api.py(模块 基准测试;类别 test;类型 test-coverage;符号 test_embedding_cache_flush_uses_the_engine_specific_endpoint): 更新测试断言,确保 vllm 和 sglang 后端在 flush_server_cache 时传递不同参数,防止回归。
关键符号:flush_server_cache
关键源码片段
python/sglang/benchmark/serving.py
核心修改文件,flush_server_cache 函数增加 timeout 参数,解决 warmup 后 flush_cache 的竞态失败。
def flush_server_cache(base_url: str, backend: str) -> None:
"""Flush an engine's prefix cache after benchmark warmup.
SGLang 服务端在 warmup 刚结束时可能还没完全空闲,直接 flush 会收到
HTTP 400,因此对非 vllm 后端传入 timeout 查询参数,让服务端在超时
窗口内轮询 is_fully_idle(),等调度器清理完残留状态后再刷新缓存。
"""
# vllm 使用 /reset_prefix_cache,其余(sglang 系)使用 /flush_cache
cache_endpoint = (
"/reset_prefix_cache" if backend.startswith("vllm") else "/flush_cache"
)
# 只有 sglang 后端需要 timeout,vllm 后端不支持该参数,传空 dict 保持原行为
params = {"timeout": 10.0} if not backend.startswith("vllm") else {}
response = requests.post(
base_url + cache_endpoint,
headers=get_auth_headers(),
params=params,
)
response.raise_for_status()
评论区精华
review 只有 sglang-npu-bot 的 APPROVED,无实质的人工讨论。Issue 评论主要是 CI 重跑命令(/rerun-failed-ci),说明 CI 曾失败过,但最终通过。
风险与影响
- 风险:主要风险包括:硬编码 timeout=10.0 可能在服务极慢时不足,但也可能掩盖服务长时间无响应的问题;参数以 query string 传递,需确认服务端 /flush_cache 支持 timeout 参数(从代码上下文看是支持的,否则会被忽略);本次只更新了单元测试 mock 断言,没有集成测试验证真实服务端行为。整体风险较低,因为只影响 benchmark 工具。
- 影响:影响 benchmark 工具的运行稳定性,特别是 CI 中跑 benchmark 的场景,减少偶发失败;对生产服务无影响,因为不涉及运行时逻辑。团队维护 benchmark 脚本的人需要知道 flush 现在可能等待最多 10 秒。
- 风险标记:硬编码 timeout 值, 单测未覆盖真实服务端, 参数可能被忽略
关联脉络
参与讨论