ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Mooncake Store 的 NVMe KV 后端设计:从逻辑对象到固定尺寸 KV 命令的落地实践

2026/10/4 9:54:30 拓冰建站 浏览量
Mooncake Store 的 NVMe KV 后端设计:从逻辑对象到固定尺寸 KV 命令的落地实践 人工智能大模型模型推理服务后端【免费下载链接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.项目地址https://gitcode.com/gh_mirrors/mo/Mooncake点击查看免费下载导读本文基于 Mooncake 开源仓库中的设计文档 docs/source/design/store/nvme-kv-backend.md系统讲解 Mooncake Store 如何通过 NVMe Key-ValueKVNamespace 扩展节点本地 SSD 卸载路径在保留 Mooncake 逻辑对象 API 的前提下将变长逻辑键/值翻译为定长 NVMe KV 物理键与受限设备值。读完本文你将掌握该后端的整体架构、物理键编码与冲突处理策略、inline/manifest 两种对象布局、写读路径的流水线与校验机制、io_uring/ioctl 两种执行器设计以及完整的环境变量配置项与默认值。背景为什么需要 NVMe KV 后端Mooncake Store 的节点本地 SSD 卸载路径FileStorage与StorageBackendInterface体系原本面向块级/文件级存储。NVMe KV 后端NvmeKvStorageBackend把这条路径扩展到 NVMe KV Namespace 之上使得一个节点内挂载的 NVMe KV 设备能够直接承载 Mooncake 对象的卸载同时保留对象语义逻辑对象 API 不变上层仍然按逻辑键 内存片Slice读写对象命令传输与对象语义解耦NvmeKvStorageBackend负责逻辑对象布局、完整性校验、键冲突处理与批量 I/O 编排NvmeKvConnector将一个配置的设备绑定到一个执行器NvmeKvCommandExecutor通过 io_uring 或 ioctl 提交 Store、Retrieve、Delete 命令。从源码结构看这一设计在 mooncake-store/include/nvme_kv/ 与 mooncake-store/src/nvme_kv/ 中体现为backend.h/cpp、connector.h/cpp、executor.h、key_codec.h/cpp、key_conflict_policy.h/cpp、object_layout.h/cpp等一组相对独立、职责清晰的模块。设计目标设计文档明确列出该后端要达成的目标它们是理解后续所有机制的主线将一个节点本地 NVMe KV Namespace集成进现有 SSD 卸载流程通过**放置校验placement validation与校验和checksums**保持对象身份与完整性支持大于单个设备值device value的逻辑对象使用store-if-not-exists实现幂等写入并显式处理物理键哈希冲突以有界并发重叠对象准备、块提交、根提交三个阶段优先使用 io_uringioctl 作为初始化兜底。架构总览设计文档给出了如下组件关系图关键点master 把对象记录为由某个 real client 拥有的LOCAL_DISK副本NVMe KV 命令只在该客户端本地执行不跨节点下发。这与 Mooncake 的整体副本模型一致——节点本地盘上的副本归属关系由控制面master追踪数据面则完全落在所有者节点内。分层职责设计文档用一个表格界定了各层的边界这也是代码模块划分的直接依据层职责FileStorage获取内存片、调用后端、上报成功副本、服务远端 SSD 读取。NvmeKvStorageBackend构建对象布局、应用键冲突策略、协调有界批量 I/O、校验设备返回的数据。NvmeKvConnector解析配置的设备、初始化时选择一个执行器、转发命令。NvmeKvCommandExecutor编码并提交 NVMe KV Store/Retrieve/Delete 命令持有传输相关缓冲区与完成处理。NVMe KV Namespace通过 Linux 设备节点执行提交的命令。在实现层面mooncake-store/include/nvme_kv/executor.h 定义了执行器接口StoreRequest、RetrieveBufferRequest、RetrieveIntoRequest三种请求结构以及Capabilitieseffective_max_value_size与queue_depth。接口注释特别强调批量调用在边界上是同步的——实现必须在返回前完成对所有请求所持缓冲区的访问并填充每个结果这为上层安全复用请求数组与 DMA 缓冲区提供了契约保障。物理键与冲突处理为什么不能直接使用逻辑键NVMe KV Namespace 通过其 KV 格式暴露键/值限制最大键长、最大值长命令完成也可能上报 invalid key/value size。Mooncake 的逻辑键是变长字符串不能原样传给设备同时 NVMe KV 命令使用16 字节物理键。因此需要一个键编解码层。键编解码Key Codeckey_codec.h 给出了核心类型与函数物理键类型NvmeKvPhysicalKey std::arrayuint8_t, 16EncodeNvmeKvPhysicalKey(identity, slot)与EncodeNvmeKvChunkPhysicalKey(identity, chunk_index, slot)分别派生根键与块键常量kNvmeKvMaxPhysicalKeySlots 64即冲突探测最多 64 个槽位ComputeNvmeKvVerifyHash生成 32 字节std::arrayuint8_t, 32的验证哈希。键派生输入包括完整逻辑键、对象角色root 或 chunk、块索引、冲突槽位。设计文档明确了两条哈希规则两个独立播种的 XXH64 值构成物理键四个独立播种的 XXH64 值构成存放在根头中的身份验证哈希。并且逻辑键的每一个字节都被保留、不丢弃也不做保留字节——编码是确定性、可重复推导的。冲突处理策略后端最多尝试 64 个冲突槽位kNvmeKvMaxPhysicalKeySlots且每次 Store 都使用 store-if-not-exists对应命令字段中的 option 0x2见下文。当物理键已存在时后端 Retrieve 现有值与期望字节比对完全相同→ 说明是同一对象操作幂等成功不同→ 判定为物理键冲突尝试下一个槽位其余设备错误原样返回给FileStorage。读路径同样推导相同的根键并逐个探测槽位直到存储的逻辑身份与请求键匹配根中的放置元数据必须与观测到的物理键 选中的槽位一致否则按校验失败处理。这套策略在 key_conflict_policy.cpp 的BuildWritePlan、ResolveExistingObject、ValidateResolvedRootPlacement中落地。对象布局inline 与 manifest设备值同样有尺寸约束每个 Store/Retrieve 必须落在有效值上限之内而 Mooncake 对象可以大于单个设备值。该上限由协议/设备上限、运行时传输上限和传输对齐三者共同决定round_down(min(protocol_max_value_size, runtime_transfer_limit), transfer_alignment)因此需要分块chunking来适配逻辑对象尺寸与受限值模型inline 根NvmeKvObjectHeader 存储的身份元数据 逻辑负载三者放在同一个设备值中manifest 根 裸块大对象先拆成若干原始块值随后写入一个根 manifest每个 manifest 记录存放物理块键、块大小、校验和根作为可见性标记只有当某对象的所有块都成功后才写该对象的根 manifestmanifest 自身必须能放进单个设备值。object_layout.h 给出了头部结构的精确定义NvmeKvObjectHeader包含magic常量0x4e564b56、object_typekInline1/kManifest2、payload_size、32 字节verify_hash、payload_checksum、header_checksum与identity_metadata_size。块记录NvmeKvManifestChunkRecord则由物理键、payload_size、payload_checksum组成。写路径BatchOffload设计文档给出了写路径的时序结合 backend.cpp 的实现细节写路径有以下几个值得注意的机制准备prepare与提交submit分离准备 worker 构建 payload 视图BuildPayloadView支持多片拼接或单片零拷贝视图、校验和、块与根 manifest独立的提交 lane 负责下发设备命令根 lane 流水线块 lane 在一个对象的所有块完成后将其立即投递给专用根 laneIndexQueueroot_submit_workers_而不是等整个批次全部完成——这是重叠对象准备、块提交、根提交的关键实现有界并发worker 数量与命令批量受NvmeKvIoConcurrencyConfig与执行器queue_depth约束RunParallelIo、RunPipelinedIo、StoreBatchParallel失败清理失败时只 best-effort 删除当前尝试创建的键作为同一对象被接受幂等命中的既有值永不删除。cleanup_new_writes对根与已写块分别 Delete并对OBJECT_NOT_FOUND之外的错误仅记录 WARNINGmanifest 缓存写成功后会把 manifest 记录写入进程内缓存CacheManifestAfterWrite下次读取可跳过根解析直接按缓存的块键与偏移发起块读取缓存以(key, payload_size)为键重写同键对象时更新。读路径BatchLoad读路径对每个请求的逻辑键解析并校验其根对象ResolveRoot按槽位 Retrieve、解析 blob、校验逻辑键与放置元数据inline 负载校验和验证后直接拷贝到目标内存片manifest 根校验后转换成块记录与当前请求的目的地偏移ValidateChunkRecords计算每个块在目标缓冲中的偏移块读取按有界任务分组ReadPlanBatchSize控制每组计划数RunPipelinedIo把读组与校验组流水化。块读取有两条路径backend.cpp 的read_group直接读当所选执行器支持直接读、且目标地址与尺寸都满足传输对齐CanRetrieveDirectlyIntosize % alignment 0且ptr % alignment 0时使用RetrieveIntoBatch让设备直接写入 Mooncake 缓冲区完成后在目标缓冲内逐一校验块校验和verify_read_group经执行器缓冲其余情况使用RetrieveBufferBatch读到执行器自有缓冲区再校验并拷贝load_chunk_blob。无论哪条路径头部、身份、放置、manifest、负载以及每个块的校验和都会在操作返回前逐一验证任何不一致都映射为FILE_READ_FAIL。执行器设计公共命令层executor_util.h 集中了物理键打包、NVMe KV opcode、三种命令的构建BuildNvmeKvStoreCommand/BuildNvmeKvRetrieveCommand/BuildNvmeKvDeleteCommand、传输对齐、对齐缓冲区分配、状态映射与能力计算。关键常量常量默认值说明kNvmeKvMaxKeySizeBytes16NVMe KV 键长上限kDefaultNvmeKvQueueDepth256默认队列深度kDefaultNvmeKvRuntimeTransferLimit270336默认运行时传输上限约 264 KiBkDefaultNvmeKvProtocolMaxValueSize512 × 1024默认协议最大值kDefaultNvmeKvTransferAlignmentBytes4096默认传输对齐kDefaultNvmeKvValueBlockUnitBytes512值块单元kNvmeKvCommandTimeoutMs30000命令超时kNvmeKvStoreIfNotExistsOption0x2Store 的 if-not-exists 选项kNvmeKvCommandSetIdentifier0x01命令集标识打包进 cdw14 高字节OpcodeStore 0x01Retrieve 0x02Delete 0x10。能力计算BuildNvmeKvCapabilities正是文档中公式的实现effective_max_value_size round_down(min(protocol_max_value_size, runtime_transfer_limit), transfer_alignment)queue_depth为 0 时回落到默认队列深度。状态映射executor_util.cpp 的MapNvmeKvStatus把 NVMe KV 状态码翻译为 MooncakeErrorCodeNVMe KV 状态码含义映射结果0x81容量超限KEYS_ULTRA_LIMIT0x85 / 0x86非法值长 / 非法键长INVALID_PARAMS0x87键不存在OBJECT_NOT_FOUND0x88不可恢复读错误FILE_READ_FAIL0x89键已存在OBJECT_ALREADY_EXISTS其他—写FILE_WRITE_FAIL/ 读FILE_READ_FAIL传输层错误MapNvmeKvTransportError则把ENOENT→OBJECT_NOT_FOUND、ENOSPC→KEYS_ULTRA_LIMIT、EINVAL→INVALID_PARAMS、ENOMEM→BUFFER_OVERFLOW映射到统一错误域。另外IsNvmeKvControlFlowError将OBJECT_NOT_FOUND与OBJECT_ALREADY_EXISTS识别为控制流错误——它们正是冲突探测循环的驱动信号。io_uring 执行器executor_io_uring.cpp 实现的核心机制线程本地 ringSharedNvmeUringRing以thread_local单例持有 ring按归一化队列深度复用避免共享热路径 ring 锁128 字节 SQEIORING_SETUP_SQE128是 NVMe uring_cmd 透传的前提struct nvme_uring_cmd约 72 字节超出默认 64 字节 SQE代码同时请求IORING_SETUP_CQE32若内核不支持则回退为仅 SQE128 重新初始化并通过ring_.flags记录cqe32_enabled_批量提交纪律维持有界在途命令数排空可用 CQE 后立即回填已释放的 SQE完成去重user_data编码代际 token 命令索引用于拒绝过期、重复与越批完成事件异常恢复部分提交失败时先排空已被内核接受的命令再重置线程本地 ringResetRing设备路径解析ResolveIoUringDevicePath会把块设备路径解析为 NVMe 通用字符设备generic char device路径后打开。ioctl 执行器executor_ioctl.cpp 构造相同的命令字段到nvme_passthru_cmd通过::ioctl(fd_, NVME_IOCTL_IO_CMD, cmd)提交。ioctl 调用在单个后端 worker 内同步执行跨请求的并行性由后端 worker 池提供——这与 io_uring 的异步批处理模型形成对照是低内核版本/无 io_uring 环境下的兜底路径。执行器选择NvmeKvConnectorConfig::transport枚举kAuto/kIoUring/kIoctl见 connector_config.h决定初始化策略auto编译开启时先尝试 io_uring仅当 io_uring 初始化失败时回退到 ioctl运行时命令失败不切换传输显式io_uring/ioctl若无法创建指定执行器初始化直接失败。并发与所有权模型设计文档总结了该后端在并发上的关键取舍后端 worker 池有界对象准备、块提交、根提交、兜底 I/O 分别由io_workers_、submit_workers_、root_submit_workers_三个线程池承载并发度由 io_concurrency_config.h 的环境变量配置驱动FromEnvironment(device_queue_depth)io_uring ring 线程本地化避免共享热路径 ring 锁竞争批量 API 边界同步请求数组与 DMA 缓冲区在其所有命令完成后才被复用这是接口层明确承诺的语义直接读后校验直接读路径在目标缓冲内完成后校验校验和分块对象的根提交顺序根只在其所有块成功后提交保证读取侧永远看到完整对象或不存在。失败语义一览设计文档给出的失败语义表完整如下条件行为键不存在返回OBJECT_NOT_FOUND。store-if-not-exists 命中相同字节视为幂等成功。store-if-not-exists 命中不同字节视为物理键冲突尝试下一个槽位。头部/身份/放置/manifest/校验和失败返回FILE_READ_FAIL。块部分写入对本次失败尝试创建的键做 best-effort 清理。io_uring 提交或完成异常排空已接受命令、重置线程本地 ring、操作失败。auto模式下 io_uring 初始化失败尝试 ioctl。运行时设备 I/O 失败返回映射后的错误不做传输切换。环境变量配置NVMe KV 后端几乎完全由环境变量驱动变量声明集中在 mooncake-common/include/environment_variables.hMOONCAKE_NVME_KV_*系列。结合 connector_config.cpp、executor_config.h 与 io_concurrency_config.h完整配置项如下环境变量默认值说明MOONCAKE_NVME_KV_DEVICE_PATH必填NVMe KV 设备节点路径为空时初始化直接失败INVALID_PARAMS。MOONCAKE_NVME_KV_NSID1Namespace ID。MOONCAKE_NVME_KV_QUEUE_DEPTH256执行器队列深度同时约束根 lane 的批大小。MOONCAKE_NVME_KV_RUNTIME_TRANSFER_LIMIT270336运行时单命令传输上限参与有效值上限计算。MOONCAKE_NVME_KV_TRANSPORTautoauto/io_uring/ioctl非法值报INVALID_PARAMS。MOONCAKE_NVME_KV_MAX_IO_CONCURRENCY256最大 I/O 并发上限。MOONCAKE_NVME_KV_IO_CONCURRENCY1io worker 池并发度。MOONCAKE_NVME_KV_BATCH_SUBMIT_CONCURRENCY1块提交 lane 数。MOONCAKE_NVME_KV_ROOT_SUBMIT_CONCURRENCY1根提交 lane 数。MOONCAKE_NVME_KV_PREPARE_CONCURRENCY1对象准备并发度。MOONCAKE_NVME_KV_TRANSFER_ALIGNMENT_BYTES4096传输对齐字节数。MOONCAKE_NVME_KV_VALUE_BLOCK_UNIT_BYTES512值块单元字节数。MOONCAKE_NVME_KV_PROTOCOL_MAX_VALUE_SIZE512 × 1024协议层最大值尺寸。MOONCAKE_NVME_KV_READ_PLAN_BATCH_SIZE由ReadPlanBatchSizeFromEnvironment()决定读路径每组计划数。配置解析器的数值字段走统一的TryParseNvmeKvU32u32_parser.cpp解析失败回落到默认值。队列深度若配置为 0BuildNvmeKvCapabilities会回落到默认 256。另外后端初始化日志会打印实际生效的 I/O 并发、批量提交并发、根提交并发与准备并发backend.cpp 的InitIoWorkers便于运行时核对配置是否按预期加载。测试与验证仓库为 NVMe KV 后端配置了专门测试mooncake-store/tests/nvme_kv/storage_backend_test.cpp 覆盖物理键打包编码命令集、KV 特有状态码映射、I/O worker 并发下依赖上限保持、后端从设备加载已知对象含BatchOffload返回对象数、IsExist命中/未命中、流水线桩往返分块对象以及同键重写后 manifest 缓存更新mooncake-store/tests/nvme_kv/connector_config_test.cpp、executor_config_test.cpp、io_concurrency_config_test.cpp 分别验证三类配置从环境变量到默认值的解析行为。这些测试直接印证了本文描述的关键行为键编码确定性、冲突/状态映射、批量写读往返、分块对象可见性根后置以及配置驱动的并发模型。小结Mooncake 的 NVMe KV 后端通过逻辑对象语义与NVMe KV 命令传输的清晰分层把节点本地 NVMe KV 设备无缝接入现有 SSD 卸载链路。其核心工程要点可以归纳为16 字节物理键 最多 64 槽位的冲突探测与幂等写入inline/manifest 两种布局与根即可见性标记的提交顺序有界并发流水线准备 → 块提交 → 根提交与 manifest 缓存io_uringSQE128/CQE32、线程本地 ring、代际 token 去重优先、ioctl 兜底的执行器选择以及贯穿读写的全链路校验和验证。结合本仓库的源码与测试读者可以沿着 backend.cpp → executor_io_uring.cpp → executor_ioctl.cpp 的调用链进一步验证上述每一项机制的落地细节。赞分享人工智能大模型模型推理服务后端【免费下载链接】MooncakeMooncake is the serving platform for Kimi, a leading LLM service provided by Moonshot AI.项目地址https://gitcode.com/gh_mirrors/mo/Mooncake点击查看免费下载相关推荐Mooncake Store重新定义LLM推理的分布式KV缓存基础设施Mooncake Store重新定义LLM推理的分布式KV缓存基础设施 在大规模语言模型推理的战场上 KVCache存储效率 正成为决定胜负的关键因素。传统人工智能大模型模型推理服务后端FoundationDB C API 完全指南网络生命周期、Future 异步模型与事务编程实战FoundationDB C API 完全指南网络生命周期、Future 异步模型与事务编程实战 FoundationDB 的 C API fdb_c 是人工智能大模型模型推理服务后端LMCache 集成 Mooncake Store 远程 KV 缓存后端安装、配置与源码原理全解析LMCache 集成 Mooncake Store 远程 KV 缓存后端安装、配置与源码原理全解析 LMCache 可以将 KV Cache 落盘到远程存储后人工智能大模型缓存抽象模型推理服务上一篇UnoPim快速入门10分钟完成安装与配置的终极教程下一篇告别图标混乱Lucide图标库5大实用代码方案让界面瞬间专业创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考