文件最后提交记录最后更新时间
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
README

KV Conductor

基于 Rust 的 KV Cache 索引服务。订阅引擎 KV 事件,维护前缀树索引,为 Coordinator 提供 缓存感知的请求路由——将请求导向已缓存最长 token 前缀的 Worker。已集成在 motor Python 包内。

快速开始

kv-conductor 以可选组件的形式随 motor wheel 发布。完整的构建和启动流程:

1. 编译二进制

cd motor/kv_conductor && cargo build --release
# 二进制产出:target/release/kv-conductor

仓库提交了 Cargo.lock;本地/CI 建议使用 --locked 以固定依赖版本。流水线加速请缓存:

  • ~/.cargo/registry~/.cargo/git
  • motor/kv_conductor/target

缓存 key 建议:{os}-{rustc版本}-{Cargo.lock hash}

如果已有预编译的二进制,可跳过此步,后续 build.sh 会自动发现并打包。

2. 构建 motor wheel

# 在项目根目录执行
bash build.sh

build.sh 会自动检测 kv-conductor 二进制:

  • target/release/kv-conductor 已存在 → 直接复制到 bin/,打包进 wheel
  • 不存在但有 cargo → 自动编译
  • 设置了 KV_CONDUCTOR_PREBUILT=/path/to/binary → 使用指定的预构建二进制
  • 都没有 → 跳过,wheel 不含 kv-conductor(其他功能不受影响)

产物:dist/motor-*.whl

环境变量

变量 默认 说明
RUST_LOG info 日志级别

3. 安装 wheel

pip install dist/motor-*.whl

安装后 python -m motor.kv_conductor 即可使用。验证:

python -c "from motor.kv_conductor import is_available; print(is_available())"
# True → kv-conductor 可用

4. 启动

python -m motor.kv_conductor --port 13333

# 或直接运行二进制
./motor/kv_conductor/target/release/kv-conductor --port 13333

缓存维护参数(均有默认值):

kv-conductor \
  --maintenance-interval-secs 30 \
  --pending-ttl-secs 60 \
  --content-ttl-secs 300 \
  --offload-ttl-secs 600

后台维护会定期清理过期的 offload/pending/content 匹配缓存、HBM 空节点和无注册引用的空索引。 TTL 清理由后台周期任务完成,ingest 路径不再执行惰性全量扫描;因此即使事件流量停止, 过期数据也会被回收。实际最长驻留时间约为对应 TTL 加一个 maintenance 周期。

注意:容器部署时,镜像内二进制路径为 /usr/local/bin/kv-conductor, 启动脚本 kv_conductor.sh 通过 exec python -m motor.kv_conductor 启动。

功能

KV Conductor 维护三层存储介质的 KV Cache 索引,按绝对覆盖终点做互斥切分后 返回各介质 *_blocks 与未加权覆盖长度 matched_tokens;介质亲和权重由 Coordinator 调度器(kv_affinity_w_*)在计分时应用。

HBM(NPU)— 统一模型

引擎 Worker 通过 ZMQ PUB 或 HTTP 将 KV 事件直接推送给 conductor。 所有后端(Mooncake / Memcache / YuanRong)的 HBM 事件链路一致:

Engine Worker                        KV Conductor
(vLLM/SGLang)
      │                                │
      │  ZMQ PUB / HTTP POST           │
      │  {type: "stored",              │
      │   token_ids, block_hashes,     │
      │   parent_hash, medium: "npu"}  │
      │───────────────────────────────>│
      │                                ├─ XXH3(token_ids) -> LocalBlockHash
      │                                ├─ RadixTree.apply_store()
      │                                │    └─ build prefix chain via parent_hash
      │                                └─ query: tree walk -> longest contiguous prefix
  • 索引结构ConcurrentRadixTree,按 token 内容哈希(XXH3)建前缀链
  • 匹配语义:最长连续前缀——从 root 走到第一个缺失即停
  • 事件源:Worker 自行上报,无需中心化 Pool
  • 介质 key:注册与事件中使用 "npu"(兼容旧值 "gpu" / "xpu"

CPU / DISK — 可选,后端相关

当启用 KV Cache 池化(Mooncake / Memcache / YuanRong)且配置了 CPU/DISK 副本时, conductor 通过两阶段匹配索引二级缓存:

Engine Worker           Pool Master               KV Conductor
      │                      │                      │
      │  [Phase 1]           │                      │
      │  offload event       │                      │
      │  {token_ids,         │                      │
      │   block_hashes,      │                      │
      │   parent_hash}       │                      │
      │──────────────────────┼─────────────────────>│
      │                      │                      │  cache hash(token_ids)
      │                      │                      │  (wait for pool confirm)
      │                      │                      │
      │                      │  [Phase 2]           │
      │                      │  pool store event    │
      │                      │  {seq_hashes,        │
      │                      │   medium: "cpu"}     │
      │                      │─────────────────────>│
      │                      │                      │  match -> insert CPU index
      │                      │                      │  keep content (TTL 300s)
      │                      │                      │
      │                      │  [Disk promote]      │
      │                      │  (optional)          │
      │                      │  {seq_hashes,        │
      │                      │   medium: "disk"}    │
      │                      │─────────────────────>│
      │                      │                      │  lookup CPU tier (or kept
      │                      │                      │   content; survives cross-
      │                      │                      │   tier remove) -> Disk index
  • 索引结构LowerTierIndexer,按 (parent_seq_hash, tokens_hash) 记录 continuation edge
  • 匹配语义
    • CPU:从 HBM 断点续查;root 链(首块副本)无条件走——更长副本不会被上游较短命中掩盖
    • Disk:从 max(HBM, CPU) 断点续查(CPU 更长时优先接 CPU);root 链同 CPU 层无条件走
  • 连续匹配:走到第一个缺失边即停;同一 worker 多条候选链(root + 断点)取绝对终点最远者
  • content 保留:pool 确认后始终保留 (tokens_hash, parent_hash)(无需配置),跨 tier 移除存活,CPU 已驱逐后、保留窗口(300s TTL)内仍可解析 Disk store;窗口关闭自动清除,内存有界(条目为 tier 数据拷贝 + 短暂迁移残留)。未确认的 offload 无 TTL、无硬容量上限,随未确认块增长,仅在匹配成功或引擎驱逐时清除

各后端的 CPU/Disk 适配差异:

后端 Pool 模型 Worker 识别
Mooncake 中心化 master,一个 ZMQ PUB IP 匹配 → 节点上所有 DP
Memcache 中心化 master,一个 ZMQ PUB 同 Mooncake
YuanRong 每节点多端口 ZMQ PUB Port 匹配 → 精确 DP

查询

Coordinator 发起查询,conductor 汇总三层介质的连续匹配 block 数

Coordinator                                  KV Conductor
      │                                        │
      │  POST /query                           │
      │  {model, block_size,                   │
      │   token_ids, tenant_id?}               │
      │───────────────────────────────────────>│
      │                                        │
      │  200 {                                 │
      │    "default": {                        │  <- tenant_id (default "default")
      │      "inst-1": {                       │
      │        "longest_matched": 640,         │  <- max matched_tokens across DPs
      │        "DP": {                         │
      │          "0": {                        │
      │            "matched_tokens": 640,      │  <- exclusive sum × block_size
      │            "npu_blocks": 3,            │  <- exclusive NPU blocks
      │            "cpu_blocks": 2,            │  <- exclusive CPU beyond NPU
      │            "disk_blocks": 0            │  <- exclusive Disk beyond max(NPU,CPU)
      │          }                             │
      │        }                               │
      │      }                                 │
      │    }                                   │
      │  }                                     │
      │<───────────────────────────────────────│

字段计算(每 DP / rank):

  1. 收集各介质绝对覆盖终点 npu_end / cpu_end / disk_end
  2. 互斥切分(优先级 NPU > CPU > Disk):
    • npu_blocks = npu_end
    • cpu_blocks = max(0, cpu_end - npu_end)
    • disk_blocks = max(0, disk_end - max(npu_end, cpu_end))
  3. matched_tokens = (npu + cpu + disk) × block_size(未加权覆盖)
  4. longest_matched = max(各 DP matched_tokens)
字段 含义
npu_blocks / cpu_blocks / disk_blocks 该 DP 互斥真实命中块数(同前缀副本只归最高优先级介质)
matched_tokens 互斥块数之和 × block_size(真实覆盖长度)
longest_matched 该实例所有 DP 的 matched_tokens 最大值

调度器读取 DP[<dp_rank>]*_blocks,按 scheduler_config.kv_affinity 中的 w_npu/w_cpu/w_disk(默认 1.0/1.0/0.0)加权后再算亲和分(见亲和性调度文档)。

启动参数

参数 默认值 说明
--port / -p 13333 HTTP 服务端口
--host :: 绑定地址(默认双栈)

API

端点 方法 用途
/register POST 注册 Worker(medium_endpoints: npu / cpu / disk
/unregister POST 注销 Worker
/query POST 按 token_ids 查询各 Worker 命中 block 数
/query_by_hash POST 使用预计算 hash 查询
/events POST 接入 KV 事件
/health GET 存活检查
/workers GET 已注册 Worker 列表

详细 API 契约见 设计文档

Motor 集成

kv-conductor 已随 motor wheel 打包。部署脚本 kv_conductor.sh 通过以下命令启动:

exec python -m motor.kv_conductor --host "$KV_CONDUCTOR_HOST" --port "$KV_CONDUCTOR_PORT"

Coordinator 通过 ConductorApiClient 与 conductor 通信。user_config.json 典型配置:

{
  "motor_coordinator_config": {
    "scheduler_config": {
      "scheduler_type": "kv_cache_affinity"
    }
  },
  "kv_conductor_config": {
    "block_size": 128,
    "npu_endpoint": "tcp://*:50090",
    "http_server_port": 13333
  }
}

npu_endpoint 模式中的 * 会被替换为 endpoint IP,端口会加上 dp_rank。 注册时写入 conductor 的 medium_endpoints key 为 "npu"

详见 KV Cache 亲和性调度文档

详细设计

架构细节、多介质适配、哈希与匹配算法见 设计文档

许可证与第三方声明

本组件主体采用 Mulan PSL v2

以下文件(或部分)为 NVIDIA Dynamo kv-router 的 Apache-2.0 衍生作品 / 策略对齐, 已保留 NVIDIA 版权与 SPDX / 归因声明;分发时须同时提供 Apache-2.0 许可证文本:

本地文件 上游路径
src/lower_tier.rs lib/kv-router/src/indexer/lower_tier.rs
src/concurrent_tree.rs lib/kv-router/src/indexer/concurrent_radix_tree.rs
src/hashing.rs lib/kv-router/src/protocols.rs(XXH3 哈希)
src/protocols.rs(部分) lib/kv-router/src/protocols.rs
src/events/vllm.rs(attention 过滤策略) lib/kv-router/src/zmq_wire/filter.rs

详见: