Skip to content

P4: KV Pool 原型(Rust)——系列切片实施计划 (P4.1–P4.9) #20

Description

@chengda-wu

P4「KV Pool 原型(Rust)」实施计划 —— 系列切片

Context

P3(跨语言联通 + 前缀复用冒烟)已合入 main(235de79)。P3 的 Rust 控制面/池子是 mock:controlplane 用扁平 HashMap<Vec, BlockMeta>(非 radix)、kv-pool 用内存 bytes HashMap、transfer/tiered-store 是空壳,无 ref/配额/GC/分层/RDMA。

P4 要把这些换成生产级 KV Pool 原型。P4 完成判据(docs/00-plan.md:230)= 单测 + micro-benchmark + 用例(无多节点要求),故跨机/RDMA/真重分布 defer 到 P5,P4 单进程 + 单测模拟。

调研已确认两个复用决策:

  • B = Dynamo kvbm-logical → fork 抽 crate(in-tree vendor),几乎零耦合,263 测试 + proptest 可跟着走,是 P4 radix/分层/驱逐地基。
  • A = Mooncake transfer-engine → P4 抄设计(Rust Transport trait + TcpTransport),P5 接入 FFI 加 RdmaTransport

已定决策(用户拍板)

  1. P4 进程边界:单进程 + 单测模拟。跨节点(传输/分片重分布)单测模拟,真跨机 defer P5。
  2. A 接入:P4 抄设计(trait+TcpTransport),P5 接入 Mooncake FFI。P4 不背 CMake+原生库 CI。
  3. B fork 形态:in-tree vendor(rust/vendor/kvbm-logical + rust/vendor/dynamo-tokens)。
  4. etcd:P4 用 in-memory mock checkpoint(CheckpointStore trait),真 etcd 接入留 P6(控制面 HA)。

架构硬约束(实现必须遵守)

  • 位置视图权威在存储控制面进程内存(单写者线性一致);etcd/CheckpointStore 只存降频 checkpoint(节点/模型/配额/revision + 位置快照),满块注册不进 etcd。
  • radix tree 是位置视图权威本身,在控制面进程内存;Router/agent 持只读镜像。
  • 统一编址 L0-L3(层=介质非位置);Location.tier∈{L0,L1,L2} 硬约束(L3 用 l3_present);L2/L3 稳态 XOR;L2=F4 恢复点,L3=SSOT。
  • ref 两级:一级本地 agent(请求引用+在途传输引用+writeback ref);二级全局汇总(控制面,最终一致,供 tier/GC)。ref 归0 ≠ 删内存,只标可驱逐候选,驱逐覆写才摘视图。
  • PutEnd 两阶段:agent 本地字节落稳(写 L2 durable)后只调一次 RegisterBlocks=PutEnd;请求结束=写回屏障(flush+ack 所有已注册 block 的 L2 写回,writeback ref 随 durable ack 归零)。满块路 writeback ref 不可驱逐;尾块路(请求结束写一次,不进 radix)。
  • 冷热判定:引用数>0 冻结 + LFU-Aging + 前缀亲和加权保护公共前缀。
  • 迁移主动(promotion/demotion+L0 预放置)+ 被动兜底(读 miss 回填/写满驱逐);后台带宽池<10%,可暂停。
  • 多模型:注册登记 model_id+revision+层数+block_spec+配额;下线级联删 radix 子树;revision 视为新命名空间。
  • 配额软/硬+借用+背压;触硬配额返回写入背压信号(请求级 shedding 仍归 gateway)。

复用决策落地

B = kvbm-logical(fork,in-tree vendor)

架构定位(纠正):kvbm-logical 是 Dynamo KVBM 三层里的逻辑层(radix + 状态机 + 驱逐,不含字节;字节在 kvbm-physical,运行时在 kvbm-engine)。源码里 BlockMetadata 是空 marker trait,BlockStore slot 存的是 metadata + presence markers,没有 Vec 字节 payload。因此它对应 lake 的 controlplane(位置视图权威);kv-pool 是 dumb 字节后端——字节 HashMap 保留,只删掉它自带的「按 hash 索引」职责(归 controlplane)。双进程不矛盾:controlplane 持视图 + 驱逐策略,pool 持字节。

fork 源:3rdparty/dynamo/lib/kvbm-logical/ + 3rdparty/dynamo/lib/tokens/(后者只为 PositionalRadixTree / PositionalLineageHash,3 文件:radix.rs/blocks.rs/lib.rs)。

直接复用:BlockRegistry(registry/mod.rs:109)、PositionalRadixTree(tokens/src/radix.rs:11,两级 DashMap 按 position 分桶)、InactiveIndex trait(pools/store.rs:54)+ backends(LruBackend/MultiLruBackend 4 段频率=LFU-Aging/LineageBackend 前缀亲和)、presence markers(registry/handle.rs:128-188)。不复用 BlockManager /BlockStore (见下驱逐边界)。

P4.1 = 纯 vendor 接入(GitHub PR #21):in-tree rust/vendor/{kvbm-logical,dynamo-tokens},业务源码零改;仅 Cargo 填实版本 / path / edition 2024。不在 P4.1 做源码改造。

fork 源码改造(随 P4.2 / P4.3 按需做,非 P4.1):

  1. InactiveIndex trait + 仅 lake 所需 backendspubLineageBackend + MultiLruBackend(对照);Authority 主路径 = LineageBackend::with_frequency(叶子≈前缀亲和 + LeafPolicy::Frequency TinyLFU≈LFU-Aging)。Lru/HashMap/Fifo/ReusePolicy 保持 pub(crate)。lake 不复用 BlockStore slot 池(见 rust/vendor/UPSTREAM.md)。
  2. EventsManager:删 BlockRegistry.event_manager 字段 + on_block_registered 调用(已有 TODO delegate,registry/mod.rs:91,113),弃用 events/publisher.rs+batcher.rs(NATS 侧)。换 lake in-process 权威 + checkpoint。
  3. LogicalLayoutHandle{G1,G2,G3,G4}(lib.rs:93)→ lake L0-L3;presence HashMap<TypeId,u32> 的 TypeId 换 Tier 枚举。
  4. check_presence 升级锁内读 = 线性一致。

lake 自补(P4.2/P4.3):controlplane 用 BlockRegistry(radix 独立,register_sequence_hash/match_sequence_hash/check_presence)+ InactiveIndex backends(驱逐策略)+ lake 薄驱动(ref→0 标候选、tier 压力取 victim 摘视图),不用 BlockManager/BlockStore;promote pipeline(抄 kvbm-engine 设计:OffloadPolicy/Pipeline,自写 demotion/promotion);位置视图权威在控制面进程内存 + checkpoint。

A = Mooncake transfer-engine(抄设计,P5 接入)

P4 抄 Transport/TransferTask/BatchDesc/切片+CQ 轮询设计(3rdparty/mooncake/mooncake-transfer-engine/include/transport/transport.hmulti_transport.h),在 rust/transfer 落 Rust trait Transport(submit_transfer/get_status/register_memory/open_segment/allocate_batch_id),P4 只实现 TcpTransport(gRPC 字节走 TcpDataService)。业务面向 trait,P5 加 RdmaTransport(bindgen+薄 FFI 接 A)零业务改动。mooncake-store(L3)依赖中心化 master → 抄设计不接入,L3 用 l3_present 标志 + 薄对象存储回填。

系列切片(依赖链 P4.1→P4.2→P4.3→{P4.4..P4.9};命名用 P4.x,勿与 GitHub PR 号混淆)

P4.1 — B vendor 落地(地基) ✅ / PR #21

  • fork kvbm-logical+dynamo-tokensrust/vendor/(纯构建接入,业务源码未改)。
  • rust/Cargo.toml 加两个 vendor 成员;UPSTREAM.md pin + LICENSE;CI cargo test -p dynamo-tokens -p kvbm-logical
  • 验证:vendor 单测全绿;三语言既有编译不受影响。
  • 不做:proto 增量(随用随加)、4 项源码改造(→ P4.2/P4.3)。

P4.2 — 内容寻址 + radix 前缀索引 + 合账骨架 + 驱逐(项 1+2) ✅

架构定位(纠正):kvbm-logical 是 Dynamo KVBM 三层里的逻辑层(radix+状态机+驱逐,不含字节;字节在 physical 层)。它对应 lake 的 controlplane(位置视图权威)。kv-pool 是 dumb 字节后端——字节 HashMap 保留,只删掉它自带的「按 hash 索引」职责(归 controlplane)。双进程不矛盾:controlplane 持视图+驱逐策略,pool 持字节。

落地澄清(相对本正文,实现切片已对齐)

  1. 命名空间:P4.2 先按 model_id 一个 BlockRegistryrevision 尚无 proto 字段,正式 (model_id, revision) 留给 P4.5。

  2. RegisterBlocks 与 lineageRegisterBlocksRequestrepeated bytes prefix_hashes(完整有序链);blocks 仍可为 miss 后缀。CP 用全链建 PositionalLineageHash

  3. EventsManager:本切片断耦不接线(builder 不设);不删 events/ 模块(物理删除留后续小 PR)。

  4. vendor pub 面 / 为何不 pub Lru·Fifo:只公开 controlplane 所需(InactiveIndex + MultiLruBackend + LineageBackend + mark_present/mark_absent;另实现 LeafPolicy::Frequency)。lake 冷热策略=ref>0 冻结 + LFU-Aging + 前缀亲和组合进 LineageBackend::with_frequency(上游 MultiLru 与 Lineage 互斥,lake 走 LeafPolicy 第三臂);MultiLruBackend 仍 pub 对照。纯 LruBackend/Fifo/HashMap 保持 pub(crate)。详见 rust/vendor/UPSTREAM.md

  • controlplane:rust/controlplane/src/lib.rs:24 扁平 HashMap<Vec,BlockMeta> → B 的 BlockRegistry+PositionalRadixTree(radix 按 position 分桶;presence markers 记 L0/L1/L2 各几份)。不用 BlockManager(它捆绑 BlockStore,见驱逐边界条)。
  • kv-pool:rust/kv-pool/src/lib.rs:16 字节 HashMap<(model_id,pool_kind,hash),Vec > 保留,删掉 lookup/索引逻辑(命中与否由 controlplane 视图决定),退化为 controlplane 指令下的纯 Put/Get。
  • hash 迁移:vendor 用 BlockHash=u64 + PositionalLineageHash(需父链 root(h0).extend(h1)...),lake 现传扁平 Vec 。决策:controlplane 建链(它拥有 registry 且依赖 vendor):收到有序 prefix_hashes 后,xxh3 Vec u64,调 PositionalLineageHash::root/extend 重建链,register/match 走 BlockRegistry。proto 的 prefix_hashes 不改,agent 保持 dumb(只转发扁平 hash+字节)。
  • 命名空间:每 (model_id,revision) 一个 BlockRegistry 实例(对齐 P4.5「按命名空间剪枝」);PositionalRadixTree 按 position 分桶,不含 model_id,靠实例隔离。
  • T = lake BlockMeta:BlockMetadata 是 blanket impl(blocks/mod.rs:56),lake BlockMeta(locations+ref_count+l3_present)直接当 T,挂在 ImmutableBlock HandleInner;vendor presence markers(HashMap<TypeId,u32>)的 TypeId 换 Tier(P4.1 改造点3),lake BlockMeta.locations 保留作位置细节权威(tier+node+segment+offset),presence 计数供驱逐/tier 逻辑。
  • ReportRef = 合账骨架(P4.2):累加 global_refs忽略 RefKind;agent 本地一级 / 分 kind → 后续。驱逐主路径=LineageBackend::with_frequency(叶子≈前缀亲和 + TinyLFU≈LFU-Aging);MultiLruBackend 对照。ref 归0 标候选不删,覆写才摘视图。 inactive 上界对齐 Dynamo:report_ref 满容只 skip insert;压力 allocate 只走显式路径(evict_n / 后续生产 allocate)。
  • 驱逐复用边界:BlockRegistry 负责 radix+presence;InactiveIndex 负责选 victim。薄驱动对齐 Dynamo 路径拆分:ref→0 → inactive.insert(满容 skip,不摘视图);压力 allocate 另路径(显式 evict_n / 后续生产,对应 allocate_atomic)。不用 BlockStore
  • 新增 proto:ReportRef(stream RefDelta)+RefDeltaRefKind wire 预留;P4.2 CP 忽略;流式全有或全无)。
  • 验证(命中 P4 判据两条):前缀复用命中率单测;驱逐正确性=Authority 单测(含 Lineage+Frequency、inactive 上界 skip insert、批内不压力驱逐);生产 ReportRef 喂数 / 压力 allocate → 后续切片。

P4.3 — 分层缓存引擎 L0-L3 + PutEnd 两阶段 + writeback ref(项 3) ✅(判据满足) / PR #31(待合)

  • rust/tiered-storeLocalTierEngine L0–L3 内存站位 + presence 经 CP publish_location/l3_present;promotion/demotion/读 miss/写满驱逐;L2/L3 稳态 XOR(写回只 L2;L3=demote/cap)。真 NVMe/对象存储 defer P5。
  • PutEnd:commit_through 时序 flush → pin → register → WRITEBACK+1 → barrier → WRITEBACK−1(durable-first COMPLETE;barrier 后才解冻,对齐 SGLang lock_ref)。
  • storage-agentControlPlanePort/AuthorityPort 进程内接线(真 tonic 客户端后续)。
  • TierPipeline + BandwidthPool(先占预算再 mutate);完整调参留 P7。
  • 验证:命中率/成本曲线单测;PutEnd/writeback 阻驱逐;benches/tier_access criterion 已跑通。
  • 合入后遗留(不挡 P4.3,记入下方 P4.7 / P5 / P6 / P7):见本 issue 评论「PR feat(P4): P4.3 完成——L0–L3 站位 / PutEnd / pipeline / 命中率验证 #31 review 遗留」——barrier 失败 inactive 窗口、WRITEBACK−1 失败永久冻结、apply_location_events 非原子、L1 无私有 CP 事件、segment 占位、lookup 懒修复写锁、hop 成本校准等。

P4.4 — TCP 数据面 + Transport 抽象(项 4,TCP-first)

  • rust/transferTransport trait + TcpTransport(gRPC 字节走 TcpDataService)。SkeletonKvService 正名为 TcpDataService(保留 PutBlocks/GetBlocks 作 TCP 字节路径,对齐 Mooncake MC_FORCE_TCP fallback)。TransferService(SubmitTransfer/GetTransferStatus/Pull/Publish)接线 TcpTransport:单进程下"传输"=本地拷贝/gRPC 字节搬运。
  • Location.tier∈{L0,L1,L2} 硬约束校验(拒绝 tier=L3)。
  • P4.3 遗留(随真介质)register_requestsegment_id:1, offset:0 占位 → P5 真 NVMe placement 填实(P4.4 若先接 TCP 段映射也可顺手,但权威在 P5)。
  • 复用:A 抄设计,不接入 Mooncake。
  • 验证:SubmitTransfer→GetTransferStatus 端到端单测;tier=L3 拒绝单测;Pull/Publish layer-wise 增量单测。

P4.5 — 多模型生命周期(项 6)

  • 模型注册/下线/revision。注册登记 model_id+revision+num_layers+block_spec+hash_algo+配额;下线级联删 radix 子树;revision 视为新命名空间。
  • 新增 proto:RegisterModel/DeregisterModel+ModelDescriptor(挂 ControlPlaneService)。
  • 复用:B PositionalRadixTree 按命名空间剪枝。
  • 验证(命中"多模型隔离"条):两模型同前缀 hash 不串扰;下线级联删(radix 子树清空+locations 摘视图);revision 失效。

P4.6 — 按模型配额 + 借用 + 背压(项 7)

  • (model_id,revision) 软/硬配额+借用;触硬配额→池返回写入背压信号(请求级 shedding 仍归 gateway,lake 只上报)。配额计数挂 P4.5 命名空间。
  • 新增 proto:SetModelQuota/GetModelQuota+Quota/BackpressureSignal
  • 验证(命中"配额"条):A 触硬配额不影响 B;借用回收;背压信号触发。

P4.7 — GC:冷块/孤儿块回收 + 崩溃 reconcile(项 8)

  • 冷块回收(ref 归0+LFU-Aging 冷度达标→摘视图+删 L0/L1 副本,L2/L3 留 durable 后盾);孤儿块回收(写入屏障标记未完成,TTL 后回收,对齐 Mooncake zombie put_start_discard_timeout);崩溃 reconcile(从 CheckpointStore 重建位置视图+agent 上报对账,元数据先于字节删除)。
  • writeback ref 泄漏兜底(P4.3 遗留):PutEndSession::commit_through 在 WRITEBACK+1 上报 CP 后、barrier(WRITEBACK-1)前若 agent 崩溃,CP 侧 global_refs 永不归零→该 prefix radix 永久冻结驱逐(泄漏)。Mooncake 走会话级 put_start_discard_timeout;lake 不做会话级 TTL,改由节点级崩溃 reconcile兜底——agent 心跳过期→扫该 agent 全部 ref 批量清 + 摘该节点 L0 location(节点下线 reconcile 本就覆盖此,writeback ref 泄漏是其子集)。即 P4.7 实现节点级 reconcile 即顺带解决,无需独立会话超时机制。
  • PutEnd barrier 失败 → inactive 窗口(P4.3 review feat(P4): P4.3 完成——L0–L3 站位 / PutEnd / pipeline / 命中率验证 #31 §4.1)register 成功后 RequestBarrier 失败会 WRITEBACK−1 回滚 +1,global_refs 可能归 0 → 立刻 inactive.insert。语义上「无人持有」正确,但真 tonic 重试 + 并发驱逐窗口需在 reconcile / sticky 持有策略中收紧(见 putend.rs 注释)。
  • barrier 成功但 WRITEBACK−1 失败(P4.3 review):CP 侧可能永久冻结;节点级 reconcile 扫泄漏 ref 一并兜底。
  • apply_location_events 非原子(P4.3 review):批量事件中途失败可留半更新视图;P4.7/后续补事务或补偿。
  • CheckpointStore trait + in-memory mock 实现(P4);真 etcd 留 P6。
  • 新增 proto:ReconcileOrphans/DiscardBlocks+OrphanReport+Checkpoint/CheckpointSnapshot
  • 验证(命中"GC"条):冷块回收正确+durable 后盾保留;孤儿块 TTL 回收;崩溃 reconcile(checkpoint 重建+元数据先于字节删);含上列 P4.3 遗留窗口单测或注入场景。

P4.8 — 碎片整理:逻辑共置 + 物理压实(项 9)

  • 逻辑共置(同前缀 block 物理邻近)+ 物理压实(回收段内空洞);后台带宽池<10%,节流可暂停。依赖 P4.7 摘块。
  • 新增 proto(可选):TriggerDefrag/PauseBackground
  • 验证(命中"碎片整理"条):压实前后段利用率;共置后前缀连续性;节流暂停可恢复。

P4.9 — 一致性哈希分片(项 5,单测;真重分布 defer P5)

  • 一致性哈希环 + shard map + 节点增删 block 所有权迁移逻辑(扩容仅迁移落新节点区间;缩容 Drain 推 L2 再下线)。P4 只单测模拟(虚拟节点环/增删区间重算/Drain 标记),不做真实跨节点字节迁移。
  • 新增 proto(可选):GetShardMap
  • 验证:环 membership 单测;扩容最小迁移;缩容 Drain 推 L2。真跨机 defer P5。

proto 增量汇总

新增 RPC(挂 ControlPlaneService,保持单服务):

RPC 用途 切片
ReportRef(stream RefDelta) -> Ack 合账骨架(忽略 RefKind;agent 未上报) P4.2
RegisterModel/DeregisterModel 模型注册/下线级联删 P4.5
SetModelQuota/GetModelQuota 软/硬配额+借用+背压 P4.6
ReconcileOrphans/DiscardBlocks GC reconcile + 显式摘块 P4.7
TriggerDefrag/PauseBackground(可选) 碎片整理+后台暂停 P4.8
GetShardMap(可选) 查 shard 分布(调试) P4.9

新增消息:RefDelta(ref_kind 枚举)、ModelDescriptorQuota/BackpressureSignalOrphanReportCheckpoint/CheckpointSnapshotShardMap/ShardEntry、各 RPC Request/Response。

SkeletonKvService → 正名 TcpDataService(保留,作 TCP 退化数据面;proto 注释 lake.proto 已留此口)。schema.proto 无需改结构(L0-L3/Tier/Location/BlockMeta 已定稿);BlockSpecModelDescriptor,不进 KVBlockID 寻址。

实施起点

先做 P4.1(纯 vendor;已由 PR #21 落地),再逐个推进 P4.2–P4.9。每个切片独立分支独立 review(走 GitHub PR 流程,不直推 main)。

验证(整体)

每个 PR 的验证见上。P4 整体完成判据(docs/00-plan.md:230):

  • 前缀复用命中率 + 驱逐正确性单测 → P4.2
  • 吞吐 micro-benchmark → P4.3
  • 多模型隔离/配额/GC/碎片整理各有验证用例 → P4.5/P4.6/P4.7/P4.8

CI:build.yml(rust fmt/clippy/build/stub-drift)持续绿;P4 新增的 vendor crate 加入 build/clippy/test 门。

关键文件

  • proto/lake.protoproto/schema.proto(proto 增量,各 PR)
  • rust/Cargo.toml(加 vendor 成员,P4.1)
  • rust/vendor/kvbm-logical/rust/vendor/dynamo-tokens/(P4.1 fork)
  • rust/controlplane/src/lib.rs(radix 权威/ref/模型/配额/GC/分片,P4.2/P4.5/P4.6/P4.7/P4.9)
  • rust/kv-pool/src/lib.rs(dumb 字节后端,删索引职责,P4.2)
  • rust/tiered-store/src/lib.rs(分层引擎+PutEnd+压实,P4.3/P4.8)
  • rust/transfer/src/lib.rs(Transport trait+TcpTransport,P4.4)
  • rust/storage-agent/src/lib.rs(本地记账/TransferService/Drain,P4.3/P4.4/P4.7/P4.9)
  • fork 参考:3rdparty/dynamo/lib/kvbm-logical/src/{registry/mod.rs,pools/store.rs,manager/mod.rs}3rdparty/dynamo/lib/tokens/src/radix.rs3rdparty/mooncake/mooncake-transfer-engine/include/transport/transport.h

遵守 CLAUDE.md reference 规则

每个切片实现前,对照 docs/research/3rdparty-reference.md + 对应分目录文档,显式说明参考了哪个实现(file:符号)、借鉴什么、lake 关键差异。P4.1/P4.2 参考 Dynamo kvbm-logical;P4.4 参考 Mooncake transfer-engine;P4.3 promote pipeline 参考 kvbm-engine OffloadPolicy/Pipeline


本 issue 由 P4 规划生成,作为 P4 系列切片(P4.1–P4.9)的总跟踪。每个切片对应的 GitHub PR 合入后在此勾选进度。

Metadata

Metadata

Assignees

No one assigned

    Labels

    P4P4 KV Pool 原型(Rust)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions