执行摘要
- 一句话:引入顶层 session_id 作为稳定请求标识
- 推荐动作:值得精读,尤其是 session 身份与 session_params 解耦的设计,以及 radix session 隐式启用模式。注意兼容性迁移。
功能与动机
PR body 指出:需要一种稳定的请求身份标识来驱动 session radix cache,而不必依赖显式的 session_params。通过顶层 session_id 简化用户交互,并且保持现有 session_params 路径不变。
实现拆解
- 在
io_struct.py 的 GenerateReqInput 和 TokenizedGenerateReqInput 中添加可选 session_id 字段,并在 normalize_batch_and_arguments 中增加互斥校验。
- 在 Rust gRPC 请求映射
request_utils.rs 的 build_text_generate_dict 和 build_generate_dict 中,当 session_id 存在时插入到请求字典。
- 在
scheduler.py 的 handle_generate_request 中,将 radix_native_session 的判断条件从 session_params.id 改为顶层 session_id,移除了对 session_params 的校验,并将 session_id 传入 Req 对象。同时调整 open_session 和 close_session 逻辑:open_session 只转发给 session_controller(传统路径),close_session 如果启用 radix cache 则调用 release_radix_session,否则调用 session_controller.close。
- 在
session_radix_cache.py 中移除 register_session 方法,将 release_session 重命名为 release_radix_session,并在 _tag_session_leaf 中加入 enable_session_radix_cache 守卫。
- 在 Engine、OpenAI、HTTP Server 等 entrypoint 添加
session_id 参数传递。
- 新增测试用例覆盖禁用缓存时不标记、传统 release 不影响 radix session、close tombstone 阻止晚期 finish 等场景。
关键文件:
python/sglang/srt/managers/scheduler.py(模块 调度器;类别 source;类型 core-logic;符号 handle_generate_request, open_session, close_session): 核心调度逻辑,修改 radix_native_session 判断条件并移除对 session_params 的校验,将 session_id 传入 Req。
python/sglang/srt/mem_cache/session_radix_cache.py(模块 缓存层;类别 source;类型 core-logic;符号 _tag_session_leaf, release_radix_session, release_session, register_session): Radix session 核心逻辑,修改了标记和释放语义。
python/sglang/srt/managers/io_struct.py(模块 请求结构;类别 source;类型 core-logic;符号 GenerateReqInput.session_id, TokenizedGenerateReqInput.session_id): 添加 session_id 字段并增加互斥校验。
rust/sglang-grpc/src/utils/request_utils.rs(模块 gRPC 处理;类别 source;类型 core-logic;符号 build_text_generate_dict, build_generate_dict): Rust gRPC 请求映射加入 session_id 传递。
test/manual/core/test_session_radix_cache.py(模块 缓存层;类别 test;类型 test-coverage;符号 test_disabled_cache_does_not_tag_session_kv, test_legacy_release_does_not_release_radix_session, test_close_tombstone_blocks_late_finish): 测试 session radix cache 新行为,包括禁用时标记、传统 release 不释放 radix session 等。
关键符号:_tag_session_leaf, release_radix_session, handle_generate_request, build_text_generate_dict, build_generate_dict
关键源码片段
python/sglang/srt/managers/scheduler.py
核心调度逻辑,修改 radix_native_session 判断条件并移除对 session_params 的校验,将 session_id 传入 Req。
def handle_generate_request(self, recv_req: TokenizedGenerateReqInput):
# 从 session_params.id 获取传统 session id
session_id = (
recv_req.session_params.id if recv_req.session_params is not None else None
)
# Radix-native sessions use only the top-level session_id.
radix_native_session = (
recv_req.session_id is not None
and self.server_args.enable_session_radix_cache
)
if session_id is None or radix_native_session:
# Normal non-session request, or a radix-native session request
# ... (mm inputs, bootstrap port, etc.)
req = Req(
recv_req.rid,
recv_req.input_text,
recv_req.input_ids,
recv_req.sampling_params,
return_logprob=recv_req.return_logprob,
top_logprobs_num=recv_req.top_logprobs_num,
token_ids_logprob=recv_req.token_ids_logprob,
stream=recv_req.stream,
lora_id=recv_req.lora_id,
session_id=recv_req.session_id, # 将顶层 session_id 传入 Req
# ... other fields
)
else:
# Legacy session request with session_params
# ...
python/sglang/srt/mem_cache/session_radix_cache.py
Radix session 核心逻辑,修改了标记和释放语义。
def _tag_session_leaf(self, req: Req, radix_key, node=None) -> None:
# 将请求的 session_id 标记到叶子节点(仅当 radix cache 启用时)
if not self.enable_session_radix_cache:
return # 缓存未启用,不执行任何操作
self._ensure_session_radix_state()
sid = getattr(req, 'session_id', None)
if sid is None or sid in self._closed_session_ids:
return
if node is None:
logger.warning(
'_tag_session_leaf 被调用时未提供 node,将回退到 match_prefix'
)
node = self.match_prefix(MatchPrefixParams(key=radix_key)).last_device_node
if node is not None and node is not self.root_node:
session_ids = getattr(node, 'session_ids', None)
if session_ids is None:
session_ids = set()
node.session_ids = session_ids
session_ids.add(sid)
self._session_leaves[sid].add(node)
def release_radix_session(self, session_id: str) -> int:
# 关闭 session:从每个标记的叶子节点中移除该 session 的持有关系
# 仅当节点不再被任何 session 持有且满足回收条件时才释放物理 KV 块
self._ensure_session_radix_state()
self._remember_closed_session(session_id)
indexed = self._session_leaves.pop(session_id, set())
freed = 0
for leaf in indexed:
if session_id not in getattr(leaf, 'session_ids', set()):
continue
node = leaf
while True:
session_ids = getattr(node, 'session_ids', None)
if session_ids is not None:
session_ids.discard(session_id)
if not session_ids:
delattr(node, 'session_ids')
# 停止条件:根节点、锁定的节点、有子节点的节点、不可逐出的节点、或被其他 session 持用的节点
if (
node is self.root_node
or node.lock_ref != 0
or len(node.children) != 0
or node not in self.evictable_leaves
or getattr(node, 'session_ids', None)
):
break
parent = node.parent
self.token_to_kv_pool_allocator.free(node.value)
self._delete_leaf(node)
freed += 1
node = parent
logger.info('released radix session %s: %d tokens freed', session_id, freed)
return freed
评论区精华
无实质 review 讨论,作者自行合并。CI 全部通过。
风险与影响
- 风险:
- 兼容性风险:新增
session_id 与 session_params 互斥约束,可能中断同时使用两者的旧请求。
- 行为变化:启用
enable_session_radix_cache 后,携带 session_id 的请求会自动开启 radix session,不再需要 /open_session,可能影响依赖显式打开的客户端。
- 废弃
register_session 方法:任何外部调用会报错,需迁移。
- 影响:影响范围中等:修改了请求定义(io_struct)、调度器核心逻辑、gRPC 映射、多个 entrypoint 和测试。对使用 session radix cache 的用户体验简化明显;对仅用传统 session 的用户无影响。
- 风险标记:session_id与session_params互斥, 隐式开启radix session, 移除register_session方法
关联脉络
参与讨论