Skip to content

NNRP/1 缓存能力与租约

缓存不是某个 runtime 的内部优化技巧,而是协议要显式表达的公共能力边界。

它在整个协议栈的位置

握手时双方协商缓存能力上限,session 打开时声明租约期望,之后在控制面完成对象安装,热路径帧直接引用而无需重传。

规范缓存身份

NNRP/1 的控制面与热路径统一使用同一种缓存身份:

text
(cache_namespace: u32, cache_key_hi: u64, cache_key_lo: u64, object_kind: u32 enum)

两个 key 字段共同组成一个不透明的 128 位值。实现不得截断任一字段,也不得派生第二套传输层私有 key。namespace 用于限定分配和批量失效范围;即使 key 全局唯一,它仍然是缓存身份的一部分。object_kind 用于避免不同对象族的相同 key 在本地对象表和租约表中发生别名冲突。24 字节热路径 Object Reference Block 使用经过校验的 u16 枚举投影;这个紧凑 wire 字段不会收窄规范本地身份或 FFI 表示。

CACHE_INVALIDATE 按 scope 使用字段:

Scope必填身份字段必须为零的字段
whole_sessioncache_namespacecache_key_hicache_key_lo
namespacecache_namespacecache_key_hicache_key_lo
object_kindcache_namespacecache_key_hi 低 32 位携带 u32 object-kind codecache_key_hi 高 32 位、整个 cache_key_lo
object_key完整缓存身份

本地缓存租约状态

所有 SDK 对已经授予的缓存租约统一使用下面的校验值模型。这个模型是本地 runtime 状态,不是第二套 wire layout,也不是 native pointer 或 handle。

语义字段宽度含义
object_id结构化值规范的 (cache_namespace, cache_key_hi, cache_key_lo, object_kind) 身份。
object_versionu64该租约覆盖的准确对象版本。
lease_idu64runtime 签发的租约身份。
owner_scopeu8 enumconnection = 0session = 1operation = 2
owner_idu64owner_scope 所选命名空间中的标识符。
granted_at_msu64租约授予时的 runtime 单调时钟时间戳。
ttl_msu32授予的租约生命周期,单位为毫秒。

SDK 可以暴露符合语言习惯的字段名,但必须保留上述值和宽度。到期时间按 saturating_add(granted_at_ms, ttl_ms) 计算;仅当 now_ms < expires_at_ms 时租约有效。使用租约访问不等于 object_version 的对象版本时,必须返回 version_mismatch。因此 TTL 为零的租约会立即到期。

缓存 wire metadata

所有整数字段均为小端序。发送方必须把 reserved 字段置零,接收方必须拒绝非零值。

Object Reference Block

这个 24 字节 block 位于热路径 object-reference region。

Offset字段类型含义
0object_kindu16缓存对象类型。
2ref_flagsu16引用 flags。
4cache_namespaceu32缓存 namespace。
8cache_key_hiu64缓存 key 高 64 位。
16cache_key_lou64缓存 key 低 64 位。

Cache Put Metadata

Offset字段类型含义
0cache_namespaceu32缓存 namespace。
4object_kindu32缓存对象类型。
8cache_key_hiu64缓存 key 高 64 位。
16cache_key_lou64缓存 key 低 64 位。
24ttl_msu32请求的租约 TTL。
28object_bytesu32对象 body 长度。
32codec_bitmapu32允许的对象 codec。
36flagsu32写入与续租 flags。

Cache Ack Metadata

Offset字段类型含义
0cache_namespaceu32缓存 namespace。
4statusu32接受状态。
8cache_key_hiu64缓存 key 高 64 位。
16cache_key_lou64缓存 key 低 64 位。
24accepted_ttl_msu32实际授予的租约 TTL。
28max_object_bytesu32接收方对象大小上限。
32detail_codeu32状态详情。
36reservedu32必须为零。

Cache Invalidate Metadata

Offset字段类型含义
0invalidate_scopeu32失效范围。
4cache_namespaceu32namespace selector。
8cache_key_hiu64key 高 64 位或 object-kind selector。
16cache_key_lou64key 低 64 位。
24reason_codeu32失效原因。
28reservedu32必须为零。

对象生命周期时序

下面展示一个低频对象从安装到被引用、再到到期失效的完整流程:

为什么还要引入租约

只有"能缓存"还不够。对象池如果没有有效期,会带来三个问题:

  • 服务端无法安全回收内存,即使对象已经很久没有被使用。
  • 宿主不知道哪些对象还有效,每次提交都得担心 cache miss。
  • 当模型更新或上下文切换时,旧对象没有明确的下线路径。

租约给每个对象配了一个可见的 TTL 和续租路径,让双方都能基于协议事件而不是超时猜测做决策。

公共层冻结什么,Profile 层冻结什么

公共层冻结(所有 profile 共享)Profile / Runtime 私有
lease contract(TTL、续租、到期策略)对象正文的字节布局
object identity(kind、namespace、version)KV-cache page 编码
dependency 关系语义GPU 内存页排布
cache miss / lease expired / dependency invalid 错误模型私有索引结构

最佳实践

安装时机:只把真正被多次引用的大对象放进缓存,单次使用的小 block 直接内联。超过 1 KB 且在同一 session 内会复用两次以上的对象值得进缓存。

TTL 选择lease_ttl_hint_ms 应当比你预期的 session 持续时间短 20–30%。如果 session 预计 60 秒,TTL 设到 40 秒并在对象还在用时主动续租,而不是等到到期后再重新安装。

失效处理:收到 CACHE_INVALIDATE 后,立即把本地引用标记为无效并在下一次提交里切换回内联 block。不要假设同一个 key 仍然有效。

版本管理:对象内容变化时换新的 cache_key,而不是复用旧 key 覆盖。这样可以避免服务端和宿主之间对"这个 key 指的是哪一版内容"产生分歧。

观测:把每次 CACHE_ACKactual_ttl_ms、每次 CACHE_INVALIDATE 的原因字段,以及命中/未命中比例记录下来。这些是判断缓存策略是否有效的唯一稳定依据。

这页和其他页的边界

  1. 连接、session、operation 的职责边界,继续看"会话与操作模型"。
  2. descriptor 与 payload 的固定布局,继续看"类型化载荷描述符"和各 profile 页面。
  3. schema 如何成为标准扩展机制,继续看下一页"Schema / Profile Registry"。

NNRP Documentation