Skip to content

Latest commit

 

History

History
314 lines (225 loc) · 23.5 KB

File metadata and controls

314 lines (225 loc) · 23.5 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;它通过 meta:cache_location 类型与 event 的 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
    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

    %% 底层通用模块被广泛依赖
    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 查询入口固定在单个节点上。


5. 修改功能前的提示

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