Skip to content

Latest commit

 

History

History
323 lines (231 loc) · 24.7 KB

File metadata and controls

323 lines (231 loc) · 24.7 KB

模块架构与关联关系

本文档描述 Tair KVCache 各模块的职责,以及模块之间的关联关系(依赖方向、控制流、数据流)。目的是在修改或新增功能时,能快速判断当前模块受哪些模块约束、又会影响到哪些模块,避免遗漏关联模块带来的隐性约束。

维护提示:当模块的职责、依赖方向或调用关系发生变化,或新增/删除模块时,请同步更新本文档与文末的 Mermaid 图,并同步更新 AGENTS.md 中的缩略图。

相关文档:基本概念ReportEvent Snapshot URI 版本方案高可用与选主机制CacheReclaimer 异步删除设计后台扫描 GC 设计配置指南优化器文档


1. 系统概览

仓库包含三个相对独立的部分:

部分 路径 说明
KVCache Manager kv_cache_manager/ 核心系统:全局 KVCache 元数据管理服务,以及配套的客户端 SDK 与推理框架连接器。本文档的主体。
HiSim hisim/ 独立的 LLM 推理仿真系统,通过回放 trace 预测 TTFT/TPOT/吞吐等指标,不依赖 Manager 运行时。
Optimizer kv_cache_manager/optimizer/ 缓存仿真与优化:既支持离线回放 KVCache 访问 trace,也提供在线 TraceQuery 服务。完整 optimizer 用于策略/容量分析;LiteHit 用最小状态精确计算多容量 full-attention LRU 命中率。

KVCache Manager 采用中心化部署,负责 KVCache 的全局元数据管理(查询、写入、容量管理),推理引擎通过 Client/Connector 接入。


2. 模块职责

以下模块均位于 kv_cache_manager/ 下。

服务端核心(自上而下的调用链)

模块 目录 职责
入口 main.cpp 构造 CommandLine 并运行,唯一依赖 service
service service/ 接入层。Server 在启动时创建并串联几乎所有组件(整个服务的装配入口);*ServiceImpl(meta/admin/debug)实现与传输无关的业务入口,grpc_service/http_service/ 是对应传输适配层,util/ 负责 proto↔领域对象转换、调用守卫与访问日志。
manager manager/ 编排层与业务核心。CacheManager 是中心门面,对外提供注册实例、查询/写入/删除 Cache、上报事件、容量回收、后台 GC 与分层迁移等能力,并协调 MetaSearcherWriteLocationManagerDataStorageSelectorCacheReclaimerCacheGarbageCollectorMigrationManagerSchedulePlanExecutor 等子组件。
meta meta/ 元数据平面。MetaIndexerManagerinstance_id 管理 MetaIndexer,维护 cache key → CacheLocation 的索引;元数据后端可插拔;meta_search_cache 做查询缓存。CacheLocation 是被广泛共享的核心类型。
config config/ 配置模型 + 注册表 + HA 协调层。定义各类配置对象;RegistryManager 持久化实例注册信息;CoordinationBackend + LeaderElector 提供一主多备的分布式选主。
data_storage data_storage/ 可插拔的 KVCache 数据存储后端。DataStorageManager 管理后端集合,DataStorageBackend 抽象存储介质,DataStorageUri 统一位置描述。

通用支撑模块(被多层复用)

模块 目录 职责
common common/ 基础设施层:日志、JSON、错误码、Redis 客户端、RequestContext(逐请求追踪上下文)、concurrent_hash_maplru_cacheloop_thread、服务发现、崩溃处理等。几乎所有 C++ 模块都依赖它。
metrics metrics/ 可观测性。MetricsRegistry/MetricsCollector 收集指标,多种 reporter(kmonitor/local/logging/dummy)上报,PrometheusExporter 通过 HTTP 暴露。
event event/ 轻量事件总线。EventManager 将领域事件分发给注册的 EventPublisher;除默认日志发布器外,OptimizerEventPublisher 会将缓存读取事件转换为 protocol 中的 TraceQueryRequest,再经 SubscriptionEventSink 交给 service 层的 gRPC 流。
protocol protocol/protobuf/ gRPC/proto 契约。定义 meta/admin/debug/kv_meta 以及 optimizer 事件流服务,生成 C++ 与 Python 桩。

客户端与连接器

模块 目录 职责
client client/ C++/Python 客户端 SDK,是推理引擎与 KVCM 之间的桥梁。对外提供 ManagerClient/RTPLLMClient 门面,内部由两条链路组成(见下):元数据面 MetaClient(经 gRPC 桩 internal/stub 调用 KVCM 服务)与数据面 TransferClient(经 internal/sdk 在推理引擎显存/内存与存储后端之间搬运 KVCache 数据)。面向外部,不被服务端核心调用。
py_connector py_connector/ 推理框架集成(Python)。将 client 接入 vLLM/SGLang/TRT-LLM,含 CUDA kernel 辅助,负责在引擎的推理流程中按正确顺序调用元数据面与数据面接口。此外自带一个纯 Python 的 HTTP 元数据面客户端 KvCacheManagerClientcommon/manager_client.py),可通过统一服务发现 URL 获取 Manager 入口,并作为 C++ MetaClient 之外的另一条元数据面通路。位于 Python 侧栈顶。

三个面的界定:本文档区分三个面——元数据面指 MetaService 的接口(GetCacheLocation/StartWriteCache/FinishWriteCache/GetCacheMeta/RemoveCache/RegisterInstance 等)及 client 侧调用这些接口的逻辑,是推理引擎读写 KVCache 的热路径;数据面指 KVCache 数据在引擎显存/内存与存储后端之间的实际搬运(TransferClient,不经过 KVCM);管控面仅指 AdminService 的接口(Storage 增删改、Instance Group 管理、账号、配置快照、运维监控、Leader 运维等),供运维/管理工具使用,不在推理引擎的读写热路径上。

client 覆盖元数据面与数据面两条链路,其对应关系如下(管控面由 AdminService 承载,不属于 client SDK 的常规链路):

链路 组件 依赖 对应 KVCM 服务端接口
元数据面 MetaClientinternal/stub:grpc_stub protocolconfigservice/util:manager_message_proto_util MetaService:GetCacheLocation / StartWriteCache / FinishWriteCache / GetCacheMeta / RemoveCache
数据面(数据搬运) TransferClientinternal/sdk data_storage(URI/common_define)、common 不经过 KVCM,直接读写存储后端

元数据面到 KVCM 有两条等价通路,最终都落到服务端同一套 *ServiceImplgrpc_service/http_service 只是传输适配层):

  1. C++ MetaClient(gRPC):走 internal/stub:grpc_stub,供 C++ 侧与经 pybind 的引擎使用。
  2. Python KvCacheManagerClient(HTTP):位于 py_connector/common/manager_client.py,用 requests 覆盖 MetaService 的全部 /api/* 端点(registerInstance/getInstanceInfo/getCacheMeta/getCacheLocation/getCacheLocationLen/getCacheLocationsByBackend/startWriteCache/finishWriteCache/removeCache/trimCache/getClusterInfo/reportEvent)。manager_uri 可直接使用 HTTP(S) 地址,也可使用通用服务发现 URL;启用 Leader 发现后,客户端以动态发现的 Manager 端点调用 /api/getClusterInfo,再根据 leader_endpoint.meta_http_port 直连 Leader,并处理 SERVER_NOT_LEADER 重试。普通 API 请求使用可配置的 request_timeout_seconds(默认 1 秒),Leader 查询保留独立的 5 秒超时。不同连接器按需选用其一。

数据面则统一走 C++ TransferClient(经 pybind),与元数据面选哪条通路无关。

client 通过 InitParams.role_type 区分角色:SCHEDULER(调度节点)只创建 MetaClient 做元数据匹配与写地址申请;WORKER(推理节点)只创建 TransferClient 做数据搬运;HYBRID 两者都有。WORKER 的存储配置由 MetaClient::GetStorageConfig() 从 KVCM 下发获得,保证与服务端一致。


3. 依赖方向与关联关系

3.1 核心依赖链

服务端核心是一条清晰的单向下降链:

service → manager → meta → config → data_storage → common
  • commonprotocol 是最底层的通用模块,被各层广泛依赖;event 的 optimizer 发布链路直接使用 protocol 定义的 TraceQueryRequest
  • metricsevent 是通用支撑模块,被 managerservice 复用。
  • service 在启动时实例化 CacheManager(注入 MetricsRegistry + RegistryManager),并通过 configLeaderElector 门控 recover/cleanup。

3.2 需要特别注意的反向边(近似环)

修改这两处时要特别小心,它们是有意为之的“向上依赖”,通过拆分细粒度 Bazel target 才避免了真正的循环依赖:

  1. common:request_contextmetrics:metrics_collectorRequestContext 会直接采集指标,因此 common 反向依赖 metrics 的采集器 target。
  2. metrics:metrics_reportermanager:cache_manager:reporter 需要读取实时 cache 状态,因此 metrics 反向依赖 manager。由于 manager 依赖的是 metrics_registry/metrics_collector,而 reporter 位于独立的 metrics_reporter target,二者不构成 Bazel 环。

3.3 客户端与 Optimizer

  • client 是独立的对外分支,仅共享 commonconfigdata_storageprotocol 以及 service/util:manager_message_proto_utilpy_connector 通过 pybind 位于 client 之上。核心服务端不依赖 client。运行时,元数据面经 gRPC(C++ MetaClient)或 HTTP(py_connector 的 Python KvCacheManagerClient)调用 KVCM 服务,数据面经 C++ TransferClient 直接读写存储后端——这几条链路是理解端到端流程的关键(见第 4 节)。
  • optimizer 负责 KVCache 访问 trace 的仿真与优化(命中率/容量分析、逐出与容量参数调优),并通过独立 online runtime/service 提供实时 TraceQuery。full-attention LRU 的在线多容量统计复用 LiteHit;在线进程还可通过通用服务发现找到全部 KVCM endpoint,在 KVCM 的 Meta gRPC 端口调用 SubscribeEvents 并直接回放事件。KVCM 不反向发现 Optimizer。

3.4 模块关系图

flowchart TD
    main["main.cpp(入口)"]

    subgraph access["接入层"]
        service["service<br/>Server / *ServiceImpl<br/>grpc · http · util"]
    end

    subgraph core["编排与业务核心"]
        manager["manager<br/>CacheManager + 子组件"]
    end

    subgraph dataplane["元数据 / 存储 / 配置"]
        meta["meta<br/>MetaIndexer · CacheLocation"]
        config["config<br/>Registry · LeaderElector · Coordination"]
        data_storage["data_storage<br/>DataStorageManager · Backends"]
    end

    subgraph crosscut["通用支撑"]
        metrics["metrics"]
        event["event"]
        protocol["protocol (proto/grpc)"]
        common["common"]
    end

    subgraph clientside["客户端侧(对外分支)"]
        client["client SDK"]
        py_connector["py_connector<br/>vLLM/SGLang/TRT-LLM"]
    end

    optimizer["optimizer(仿真与优化)"]

    %% 核心下降链(控制流)
    main --> service --> manager --> meta --> config --> data_storage --> common

    %% 通用支撑依赖
    manager --> event
    event --> protocol
    manager --> metrics
    service --> metrics
    service --> event
    service --> config
    service --> data_storage
    service --> protocol
    manager --> protocol
    event --> protocol
    config --> protocol
    meta --> config
    meta --> data_storage

    %% 有意的反向边(近似环,见 3.2)
    common -. request_context .-> metrics
    metrics -. metrics_reporter .-> manager

    %% 客户端分支
    py_connector --> client
    client --> config
    client --> data_storage
    client --> protocol
    client --> common
    client -. proto 转换复用 .-> service

    %% optimizer 的关联
    optimizer -. cache_location 类型 .-> meta
    optimizer --> common
    optimizer --> protocol
    optimizer -. gRPC SubscribeEvents(运行时) .-> service

    %% 底层通用模块被广泛依赖
    meta --> common
    config --> common
    data_storage --> common
    metrics --> common
    event --> common
Loading

图例:实线箭头表示“依赖 / 调用”;虚线箭头表示需要特别注意的反向边或弱耦合。


4. 关键运行时流程(控制流 + 数据流)

完整的端到端流程涉及三方:推理引擎(经 py_connector)client(元数据面 + 数据面)KVCM 服务端。关键点在于:元数据操作走元数据面到 KVCM,实际 KVCache 数据搬运走数据面直连存储后端,二者不混。KVCM 只管理“数据在哪、能不能读写”,不经手数据本身。元数据面到 KVCM 有两条等价通路——C++ MetaClient(gRPC)或 py_connector 的 Python KvCacheManagerClient(HTTP /api/*),下文以“元数据面”统称;数据面统一走 C++ TransferClient

服务端内部流程都以 RequestContext 贯穿,指标采集在链路上逐层进行。HA 部署下只有 Leader 处理读写请求;client 先经 GetClusterInfo 发现 Leader 再直连(详见 ha_leader_elector.md)。

4.1 服务端请求的通用路径

一次元数据面请求进入 KVCM 后:

client(MetaClient/gRPC)→ service(grpc 适配 → *ServiceImpl)
    → manager(CacheManager)→ meta(索引)/ data_storage(存储状态)→ common

4.2 实例注册

推理引擎启动时经 client 注册实例,CacheManager::RegisterInstance 校验并落库实例配置(block_size、location spec、模型部署等)到 RegistryManager(config),并在 MetaIndexerManager 中为该 instance_id 建立索引。约束:KVCache 仅在同一 instance_id 内复用,跨 Instance 不匹配。

4.3 读取(命中并加载 KVCache)

从完整视角看,读取由推理引擎驱动,client 的两条链路依次参与:

  1. 匹配:引擎经 ManagerClient::MatchLocation(元数据面)调用 KVCM CacheManager::GetCacheLocation(sByBackend)。KVCM 内部由 MetaSearchermeta_search_cacheMetaIndexer 查得 CacheLocationDataStorageSelector 依据后端可用性/水位选出返回哪个存储位置,返回一组存储位置 URI(Locations)。支持前缀匹配、滑动窗口匹配、批量匹配等查询类型。
  2. 加载:引擎拿到 URI 后,经 ManagerClient::LoadKvCaches(数据面 TransferClient)由对应 SDK 从存储后端把 KVCache 数据读入引擎显存/内存。此步不经过 KVCM

4.4 两阶段写入(申请地址 → 写入 → 确认)

为保证数据可靠性,写入分两阶段,同样由引擎驱动、两条链路配合:

  1. 申请写地址(StartWriteCache):引擎经 ManagerClient::StartWrite(元数据面)调用 KVCM CacheManager::StartWriteCache。KVCM 过滤掉已存在的 block,经 DataStorageSelector 选择存储后端,由 WriteLocationManager 生成写入地址,返回 write_session_id 与写入位置 URI,对应 CacheLocation 进入 writing 态。
  2. 写入数据(SaveKvCaches):引擎经 ManagerClient::SaveKvCaches(数据面 TransferClient)把 KVCache 数据写入返回的存储位置。此步不经过 KVCM
  3. 确认(FinishWriteCache):引擎经 ManagerClient::FinishWrite(元数据面)回调 KVCM,CacheManager 依据 success_block_mask 将成功的 CacheLocation 置为 serving 并写入元数据索引;失败的 block 不会转正,保证只有真正写成功的数据可被后续读取命中。

4.4.1 端到端时序(读取与写入)

sequenceDiagram
    participant E as 推理引擎<br/>(py_connector)
    participant M as 元数据面<br/>(MetaClient/gRPC<br/>或 Python/HTTP)
    participant T as TransferClient<br/>(数据面)
    participant K as KVCM 服务端
    participant S as 存储后端

    Note over E,S: 读取流程
    E->>M: 匹配 (MatchLocation / getCacheLocation)
    M->>K: GetCacheLocation (gRPC 或 HTTP)
    K-->>M: Locations (URIs)
    M-->>E: 命中的 URI
    E->>T: LoadKvCaches(URIs, 显存 buffers)
    T->>S: 读取 KVCache 数据
    S-->>E: 数据载入显存

    Note over E,S: 写入流程(两阶段)
    E->>M: 申请写地址 (StartWrite / startWriteCache)
    M->>K: StartWriteCache (gRPC 或 HTTP)
    K-->>M: write_session_id + 写入 URI
    M-->>E: 写地址
    E->>T: SaveKvCaches(URIs, 显存 buffers)
    T->>S: 写入 KVCache 数据
    S-->>E: 写入完成 (success_mask)
    E->>M: 确认 (FinishWrite / finishWriteCache)
    M->>K: FinishWriteCache (gRPC 或 HTTP)
    K-->>E: 确认 (serving)
Loading

4.5 容量回收(后台异步)

CacheReclaimer 依据 Quota 与存储水位选出待逐出的 key,并把 Location 删除作为端到端异步任务提交给 SchedulePlanExecutor。Executor worker 完成元数据 Get/CAS/Sync;Sync 成功后通过定时队列等待删除 delay(等待不占 worker),随后删除 data_storage 数据并 CAD meta 索引。Reclaimer 在任务终态前按 Instance Group 与 BaseStorageType 维护 pending Location、删除 bytes credit 和硬配额,用于去重、避免过度逐出及提供有界反压;回收动作通过 event 上报。完整生命周期和异常语义见 CacheReclaimer 异步删除设计

4.6 分层存储迁移(异步 Prepare 与回收协同)

分层迁移由 CacheReclaimer 根据 migration strategy 的 source storage 类型水位触发。Reclaimer cron 线程只完成 LRU 候选采样、同轮回收准入和异步 Job 构造,不在 cron 线程执行可能较慢的 Backend Create、最新 Location 查询或 Copy:

  1. 同一轮先执行 Reclaim 准入。删除请求被 Executor 接受后,Reclaimer 会同步把精确的 (instance_id, block_key, location_id) 记入 pending_locations_
  2. 再构造 Migration Prepare Job。Job 携带候选 block 以及按 block 组织的 pending Location 快照,并完全持有跨异步边界所需的输入;Executor worker 不直接访问 Reclaimer 的可变状态。
  3. MigrationManager worker 重新读取当前 Instance、配置、strategy 和 Location,排除快照中的待删除 Location,再执行 Backend Create 以及统一的 Copy/Mark 准入与分发。配置已删除、Leader generation 已变化或 lifecycle gate 已关闭时,旧 Job 直接失效。
  4. Copy 完成后再次校验精确 source Location 仍为 SERVING 且 create time 未变化;若跨轮回收已经删除或替换 source,则不提升目标 Location,并清理本次生成的目标。

上述顺序只保证“同轮先做 Reclaim 准入”,不等待物理删除完成;当水位只达到 migration threshold 而未达到 reclaim threshold 时,迁移仍可独立触发。Admin 发起的迁移保持同步 Prepare 语义,但与 Reclaimer 路径复用 MigrationManager 的统一分发、活跃任务表和 Instance Group Copy 并发硬限制。

Reclaim、系统任务和 Migration 共用进程级 SchedulePlanExecutor。ready task 按 Reclaim → System → Migration Continuation → Migration Prepare 的顺序选择;Prepare、Copy 和迁移 cleanup 共同受 migration worker budget 约束。budget 必须小于线程池总大小,以保证长时间 Backend Create/Copy 不能占满所有 worker,至少有一个 worker 不会被 Migration 占用。任务优先级只影响尚未运行的任务,不能抢占已经执行的任务。参数约束和默认值见配置指南

Migration 的背压分两层:活跃 Copy 数与 queued/running Prepare 数用于 Reclaimer 的跨轮提前剪枝,MigrationManager::BatchSubmit 再对 Instance Group Copy 并发做原子硬准入。同一 generation + instance group + instance + source + target 最多存在一个 queued/running Prepare,避免 Backend Create 变慢时 cron 重复堆积同一路由。Copy 路径还会在目标 CLS_WRITING 对 Reclaimer 可见前写入 active-task reservation,防止孤儿清理误删正在准备或执行的目标。

flowchart LR
    subgraph cron["CacheReclaimer cron(单线程状态)"]
        sample["采样 / LRU 候选"]
        reclaim["Reclaim 准入"]
        pending["pending_locations_"]
        snapshot["按 block 复制 pending 快照"]

        sample --> reclaim
        reclaim --> pending
        sample --> snapshot
        pending --> snapshot
    end

    subgraph executor["共享 SchedulePlanExecutor"]
        reclaim_task["kReclaim<br/>Get / CAS / Sync / Delete"]
        prepare["kMigrationPrepare<br/>fresh 校验 / Backend Create / 分发"]
        continuation["kMigrationContinuation<br/>Copy / cleanup"]
    end

    migration["MigrationManager<br/>统一 Copy / Mark 准入与活跃任务表"]
    monitor["MigrationManager monitor<br/>完成校验 / promote / cleanup"]

    reclaim -->|优先入队| reclaim_task
    snapshot -->|Async Prepare Job| prepare
    prepare --> migration
    migration --> continuation
    continuation --> monitor
    migration -->|Mark| meta["MetaIndexer"]
    migration -->|Create target| storage["DataStorageBackend"]
    monitor --> meta
    monitor --> storage
    reclaim_task --> meta
    reclaim_task --> storage
Loading

4.7 后台 metadata GC

CacheGarbageCollector 只在 Leader 上运行,复用公共 LoopThread,按 Registry 快照和 backend cursor 串行扫描 authoritative metadata;扫描协调不占用共享的删除 worker。维护扫描不更新在线 LRU/revisit,也不向 local hot cache 回填。V1 识别超过 grace、且不属于活跃 Migration Copy 目标的 CLS_WRITING,并对普通 CLS_SERVING Location 按 storage 批量调用低成本 MightExist(),任一 spec 明确 missing 时选择整个 Location;EventReport 和探测不确定项均跳过。两类候选都通过 SchedulePlanExecutor::SubmitAsync 提交扫描时的完整序列化 Location,由 Executor worker 重新读取并以精确值条件 CAS 仲裁并发 Finish、Location 刷新和 Reclaimer。GC 使用固定小窗口管理在途 Future,并以 Instance-aware pending target 覆盖 accepted 到 CAS 的重复窗口;每 tick 最多提交一个请求,窗口满后停止扫描,完整 round 后进入长 cooldown。详细边界见 后台扫描 GC 设计

4.8 HA 故障转移

LeaderElector(config)基于 CoordinationBackend(memory/file/redis)的分布式锁选主。Server 在成为 Leader 时调用 CacheManager::DoRecover 恢复状态,随后启动 GC、恢复 Reclaimer、启动 MigrationManager 并开放 leader-only 请求。降级时先通知 GC/Reclaimer 停止新工作并关闭、排空 leader-only 请求,再 join GC、停止 MigrationManager,最后调用 DoCleanup 清理运行时状态(正在进行的写入按失败处理)。Python KvCacheManagerClient 使用服务发现 URL 时,会在每次 Leader 刷新前重新选择一个 Manager 发现端点,避免把 Leader 查询入口固定在单个节点上。

4.9 KVCM 到在线 Optimizer 的事件流

CacheManager 在读取路径产生 CacheGetEventEventManager 将其同时交给各 publisher。启用 optimizer publisher 后,单 worker 按事件顺序转换为 TraceQueryRequest,再写入每个 gRPC 订阅者的独立有界队列。KVCM 的 OptimizerEventStreamService 注册在现有 Meta gRPC server 上,不新增端口。

Optimizer 作为客户端通过 ServiceDiscoveryFactory 获取 KVCM seed endpoint,再调用 MetaService.GetClusterInfo 定位当前 Leader;任意时刻只向 Leader 保持一条 SubscribeEvents response stream。supervisor 周期刷新服务发现和 Leader,并通过同一 Meta gRPC 端口上的 OptimizerEventStreamService.GetConfiguration 拉取 Instance Group / Instance 快照,按 Group 后 Instance 的顺序自动注册新增配置;未知 instance_id 会立即触发一次额外刷新。切主时先同步配置,再迁移 stream。stream 收到事件后直接调用 OnlineOptimizerManager::TraceQuery,Optimizer 侧不再增加业务队列。


5. 修改功能前的提示

修改某个模块前,先对照第 3 节的依赖关系图与第 4 节的运行时流程,确认它的上游(谁依赖它、会被它影响)和下游(它依赖谁、受谁约束),不要遗漏被依赖方带来的约束。尤其注意 3.2 的两条反向边、CacheLocation 的生命周期与状态流转约束,以及改动 protocol proto 时需遵循 proto 修改指南