执行摘要
- 一句话:修复 cache_salt 隔离失效的 extra_key 传递 bug
- 推荐动作:该 PR 是典型的数据传递断裂 bug,代码改动量小但影响面大——直接破坏安全特性。推荐精读以理解 SGLang 请求处理链中 Req 构造的关键节点,建议未来类似 feature 在 PR 中增加端到端集成测试。
功能与动机
Issue #9163 提出的 cache_salt 安全隔离功能部署后未生效:不同 cache_salt 的请求本应使用不同的前缀缓存 key,但由于 extra_key 字段在请求链路(从请求入口到 Scheduler 构造 Req 对象)中断裂,所有请求实际使用相同的缓存 key,使得不同 tenant 之间的缓存隔离彻底失效。这直接违背了 feature 的设计目标——防止多租户场景下前缀缓存泄露隐私(参考《Leaking Secrets from Prefix Caches》论文提出的威胁模型)。
实现拆解
- 在 Scheduler 入口补传 extra_key:在
python/sglang/srt/managers/scheduler.py 的 handle_generate_request 方法中,在构造 Req 对象时新增 extra_key=recv_req.extra_key 参数。该参数原本已存在于 recv_req 对象中,但由于未显式传递给 Req 构造函数,导致字段静默丢失。这是核心修复。
- 在 Session 路径同时补传 extra_key:在
python/sglang/srt/session/session_controller.py 的 create_req 方法中,同样新增 extra_key=req.extra_key 字段。虽然 Session 场景使用 cache_salt 的场景较少,但保持入口一致性,避免未来出现类似的隔离失效问题。
- 增强测试能力:在
test/manual/openai_server/features/test_cache_report.py 中新增 _get_cached_tokens 静态方法将 prompt_tokens_details 的 None 检查封装为 0 值兜底,减少重复代码。同时调整 test_cache_salt_effectiveness 中的断言逻辑:将原来判定 cached_tokens 完全不变的 assert 改为 cached_tokens_2_second > cached_tokens_2_first,即验证不同 salt 隔离下相同 salt 仍能命中(cached_tokens 增长),使得测试逻辑更贴近实际缓存行为。还新增了 --attention-backend=triton 的启动参数,确保测试环境一致。
关键文件:
python/sglang/srt/managers/scheduler.py(模块 调度器;类别 source;类型 core-logic;符号 handle_generate_request): 核心修复点:在 handle_generate_request 中补传 extra_key 到 Req 构造函数。
python/sglang/srt/session/session_controller.py(模块 会话管理;类别 source;类型 entrypoint;符号 create_req): 同步修复 Session 路径中 Req 构造缺失 extra_key 的问题。
test/manual/openai_server/features/test_cache_report.py(模块 缓存报告;类别 test;类型 test-coverage;符号 get_cached_tokens, test_cache_salt_effectiveness): 测试用例增强:提取 get _cached _tokens 辅助方法、调整断言逻辑并增加运行参数。
关键符号:handle_generate_request, create_req, _get_cached_tokens, test_cache_salt_effectiveness
关键源码片段
python/sglang/srt/managers/scheduler.py
核心修复点:在 handle_generate_request 中补传 extra_key 到 Req 构造函数。
# python/sglang/srt/managers/scheduler.py 中的 handle_generate_request 方法(约第 1878 行)
# 修复前:extra_key 字段未从 recv_req 传递到 Req,导致 cache_salt 隔离失效
# 修复后:显式传递 extra_key,使前缀缓存 key 能区分不同 cache_salt
# 构造 Req 对象时补传 extra_key
req = Req(
rid=recv_req.rid,
origin_input_text=recv_req.origin_input_text,
origin_input_ids=recv_req.origin_input_ids,
origin_input_ids_unpadded=recv_req.origin_input_ids_unpadded,
sampling_params=sampling_params,
lora_id=recv_req.lora_id,
session=recv_req.session,
custom_logit_processor=recv_req.custom_logit_processor,
stream=recv_req.stream,
return_logprob=recv_req.return_logprob,
top_logprobs_num=recv_req.top_logprobs_num,
token_ids_logprob=recv_req.token_ids_logprob,
vocab_size=self.model_config.vocab_size,
eos_token_ids=self.model_config.eos_token_ids,
require_reasoning=recv_req.require_reasoning,
return_hidden_states=recv_req.return_hidden_states,
return_routed_experts=recv_req.return_routed_experts,
priority=recv_req.priority,
routing_key=recv_req.routing_key,
extra_key=recv_req.extra_key, # 修复:补传该字段
http_worker_ipc=recv_req.http_worker_ipc,
dllm_config=self.dllm_config,
time_stats=recv_req.time_stats,
)
python/sglang/srt/session/session_controller.py
同步修复 Session 路径中 Req 构造缺失 extra_key 的问题。
# python/sglang/srt/session/session_controller.py 中的 create_req 方法(约第 235 行)
# 修复前:extra_key 未传递,Session 中 Req 的缓存隔离同样失效
# 修复后:与调度器路径保持一致
new_req = Req(
rid=req.rid,
origin_input_text=None,
origin_input_ids=input_ids,
origin_input_ids_unpadded=input_ids_unpadded,
sampling_params=req.sampling_params,
lora_id=req.lora_id,
session=self,
custom_logit_processor=req.custom_logit_processor,
stream=req.stream,
return_logprob=req.return_logprob,
top_logprobs_num=req.top_logprobs_num,
token_ids_logprob=req.token_ids_logprob,
vocab_size=vocab_size,
eos_token_ids=eos_token_ids,
require_reasoning=req.require_reasoning,
return_hidden_states=req.return_hidden_states,
return_routed_experts=req.return_routed_experts,
priority=req.priority,
routing_key=req.routing_key,
extra_key=req.extra_key, # 修复:补传该字段
http_worker_ipc=req.http_worker_ipc,
time_stats=req.time_stats,
)
评论区精华
该 PR 没有产生 Review 评论,但从 PR 描述和提交历史来看,Contributor 基于 Issue #9163 发现并定位了 extra_key 断裂问题。Reviewer hnyls2002 直接批准,说明变更正确性较为明显。
风险与影响
- 风险:
- 回归风险低:修复仅涉及参数传递,未改变 Req 构造以外的逻辑。测试文件中断言条件的调整(从严格相等改为大于)反而更符合缓存系统的实际行为,降低了误判风险。
- Session 场景可能未被充分覆盖:虽然 session_controller.py 补充了 extra_key,但现有测试用例未对 Session 中使用 cache_salt 的场景进行验证,存在潜在遗留问题。
- 测试环境约束:测试新增了
--attention-backend=triton 参数,若未来有其他 attention 后端与该参数冲突,该测试可能失效。
- 影响:
- 用户影响:所有使用 cache_salt 的多租户部署用户将受益,缓存隔离得以正确生效;此前已部署但未生效的用户需要升级后方可获得隔离。
- 系统影响:无性能影响,extra_key 字段在请求对象中早已存在,仅传递路径补齐。
- 团队影响:提醒团队在 feature 开发时需关注长调用链中参数的完整性,建议增加集成测试覆盖跨模块参数传递。
- 风险标记:核心路径变更, 缺少 Session 场景测试覆盖
关联脉络
- PR #9163 [Feature] Support Cache Salting for secure prefix caching: 本 PR 修复了该 feature 的传递断裂 bug,是功能实现的必要补丁。
参与讨论