Mooncake 专项:面试题与参考回答
白话导读:Mooncake 方向的面试题与参考回答:基础容量、Store 与 TE、性能与故障。
- 重点题:Put 为什么分 start/end、Get 如何防止读到已回收数据、租约和 TTL 的关系、pin 能否保证不丢。
- 与专家深挖问答重叠的题,以深挖问答为主答案。
回答时说明依据的源码版本。
以下 50 题按推理 Infra 与 KV Cache 存储岗位的典型考查方向编排,不代表某家公司的真实题库或频率统计。回答应先给结论,再解释机制、取舍和证据;涉及性能时主动说明模型、硬件、负载和版本。
“正确回答”也有适用条件。本章区分标准 Transformer、当前 C++ Store 实现与通用系统设计,不把某个版本的配置当成通用定律。
一、基础与容量:Q1–Q12
Q1. KV Cache 为什么能加速自回归生成?
参考回答:相同模型与历史前缀下,已有位置的 K/V 不需要因追加 token 而重新计算。每步只计算新 token 的相关状态,并用新的 Q 读取已有 K/V。它省去了重复前向计算,但标准全注意力仍随上下文长度读取历史 KV,不能说 decode 成本与上下文无关。
追问:为什么不存 Q?后续步骤主要需要新 Q 和历史 K/V,历史 Q 通常不会再次用于新 token 的 attention。
Q2. Prefill 与 Decode 的瓶颈有什么不同?
参考回答:Prefill 可以并行处理多个输入 token,较容易形成高效矩阵运算;Decode 的每条序列逐步生成,常受权重/KV 读取和批调度限制。长 prefill 通常偏计算密集、小 batch decode 通常偏带宽密集,但 batch、attention 类型、量化、MoE 和硬件会改变结论。
常见错误:把“prefill 永远 compute-bound、decode 永远 memory-bound”当定理,不用 profiler 验证。
Q3. 如何计算 KV Cache 大小?
参考回答:标准等宽 MHA/GQA/MQA 用 2 × 层数 × KV heads × head_dim × token数 × 每元素字节数,多个请求对各自 token 数求和。L=32、Hkv=8、d=128、BF16 得到 128 KiB/token,8K token 是 1 GiB。实际预算还要加 block 对齐、元数据、量化 scales、在途 buffer 与冗余。
追问:1 GiB 是每卡吗?这是本例全模型一份逻辑 KV,是否均匀分到每卡取决于 TP/PP 和具体实现。
Q4. GQA、MQA、MLA 对存储有什么影响?
参考回答:GQA/MQA 减少 KV heads,降低每 token 容量及读取流量;MLA 可能存压缩 latent 和独立位置相关状态。MLA 必须按当前引擎实际缓存张量求和,不能机械套用标准 K/V heads 公式。不同实现还可能在计算时物化其他状态。
Q5. TP=8,KV 就一定减少到每卡八分之一吗?
参考回答:只有 KV 能均匀分片且无复制时才成立。KV heads 少于 TP、MQA/MLA、某些 kernel 或 layout 可能要求复制或特殊划分。要读实际 KV tensor shape 和 rank mapping;TP shards 是互补数据,不是容灾副本。
Q6. PagedAttention、prefix caching、FlashAttention 有何区别?
参考回答:PagedAttention 管逻辑 block 到物理块的映射,改善分配与共享;prefix caching 决定已计算的前缀能否跨请求复用;FlashAttention 优化 attention 的计算和内存访问。三者可协同,均不自动提供完整的跨节点对象存储。
Q7. 相同的一段文本为什么不能直接复用 KV?
参考回答:深层 KV 依赖前面的上下文,位置编码、模型权重和 adapter 也会改变状态。相同片段若处于不同前缀,通常不能精确复用。标准 prefix cache 的 key 应表达前面的 hash、当前 token IDs 和影响计算语义的附加信息。
Q8. 你如何设计一个可靠的 cache key?
参考回答:先定义共享兼容性边界,再用稳定序列化编码模型 revision、必要的输入/位置/adapter 信息、前缀链式 hash,以及 layout/shard 身份。把 tenant/release/cache salt 纳入隔离域。不是所有参数都需要入 key,例如 temperature 通常不改变既有 prompt KV;关键是覆盖影响状态的因素。
追问:使用 SHA-256 就充分了吗?不充分,安全哈希不能修复漏掉模型版本或 prefix 的错误 key 设计。
Q9. 全前缀命中后为什么还需要计算?
参考回答:框架仍要准备 logits/首 token、调度、采样和加载 KV;一些实现会保留或重算最后一个 prompt token。后续 decode 也必须计算新 token。缓存前缀不等于缓存了整个回答,TTFT 不会变为零。
Q10. KV 量化怎么评估?
参考回答:低精度降低容量和搬运量,但要加 scales/对齐开销,确认 kernel 和存储布局支持,并评估量化/反量化成本。除 TTFT/ITL 外要测试任务质量、长上下文和目标模型。权重量化与 KV 量化是独立决策,不能看到 INT4 权重就认为 KV 也是 INT4。
Q11. TTFT、TPOT、ITL、goodput 如何定义?
参考回答:TTFT 是请求到首 token;ITL 是相邻输出 token 间隔;常见 TPOT 是首末 token 时间差除以生成间隔数。Goodput 是单位时间满足指定 SLO 的成功请求数,要报告 offered load、错误和拒绝。平均 token/s 不能代替用户尾延迟。
追问:单 token 输出的 TPOT 怎么算?没有生成间隔,应标为不适用或按工具明示的特殊口径处理。
Q12. 缓存命中率越高,系统越好吗?
参考回答:不一定。远端命中可能耗费更多加载、排队和同步时间,预取也可能抢占 decode 资源。要区分请求/token/byte 命中率,并测成功加载的前缀、实际跳过的计算和 SLO goodput。
二、Mooncake Store 与 TE:Q13–Q27
Q13. 用两分钟介绍 Mooncake 架构。
参考回答:论文围绕 KV 复用、PD 分离和 SLO 调度设计整体推理系统。当前开源主线中,Store 管共享对象、资源、副本和租约,TE 负责高效字节移动;vLLM/SGLang 负责模型执行与请求调度,LMCache/HiCache 可负责上层分层缓存。Conductor 提供全局前缀位置索引,具体路由策略仍由上层使用它完成。
常见错误:把 Store Master 画成所有 KV payload 的中转站,或认为安装 Store 就完整复现了论文调度系统。
Q14. 为什么要分离控制面与数据面?
参考回答:Master 返回对象位置和保护状态,Client 直接从持有数据的节点搬运大块 KV,避免中心节点转发所有 payload。这样数据带宽可横向扩展,但 Master 仍要承担元数据 QPS、内存、锁和分配压力,必须单独容量规划。
Q15. Store Master 与 metadata server 是同一个吗?
参考回答:逻辑职责不同。Master 管 (tenant,key) 到副本、租约等对象状态,传输 metadata 负责 segment、内存和连接信息交换。HTTP metadata 可以内置在 Master 进程;也有 etcd/P2P handshake 等路径,但同进程不等于同一类状态。
Q16. 描述一次 Put,为什么需要 start/end?
参考回答:Client 先向 Master 请求分配并获得副本描述,再直接写 payload,满足完成条件后提交 PutEnd;失败路径撤销或返回错误,崩溃残留由超时清理。这样分配中的副本不会过早对读者可见。这个协议不代表多 key 原子事务。
源码证据:mooncake-store/src/client_service.cpp 的 Client::Put 和 DetermineFinalizeDecision 调用处。
Q17. 同一个 key 连续 put 不同 value,会覆盖吗?
参考回答:当前普通 Client::Put 遇到 OBJECT_ALREADY_EXISTS 可以直接返回成功,不保证覆盖。内容寻址系统依赖同 key 内容一致;需要更新时研究 upsert 的当前限制,或使用版本化新 key。不能仅凭返回 0 就证明旧数据已被替换。
Q18. Get 如何防止读到已回收的数据?
参考回答:先从 Master 得到可读副本和读 lease,正常删除/淘汰受租约保护。Client 完成读取后检查 I/O、适用 checksum 和租约有效性;过期或失败就不能使用本次结果。get_into 的目标内存即便已改变,也必须依据返回结果决定能否消费。
Q19. Lease 和 TTL 是什么关系?
参考回答:读 lease 是保证一段时间内安全访问的协议状态;业务 TTL 是希望数据复用到什么时候。Mooncake 的 lease TTL 控制保护窗口,不应自动理解为“对象保存这个时间后必删”。扩大 lease 能覆盖更慢的读,但会延迟回收、放大内存压力。
Q20. Soft pin 和 hard pin 能保证数据不丢吗?
参考回答:它们主要约束淘汰。Soft pin 在有效期内提高保留优先级,是否允许内存不足时淘汰受配置影响;当前读取不续 soft pin。Hard pin 跳过普通淘汰,但都不能抵抗数据节点掉电或替代持久化/副本保证。
Q21. replica_num=2 是否等于可容忍任意一台机器故障?
参考回答:要先确认实际分配了两个副本、两者都完成,并且处在不同物理故障域。当前内存分配存在 best-effort 路径,segment 隔离也不等于 host/rack 隔离。副本会提高可用性与读热点承载,同时减少有效容量、增加写流量和元数据。
Q22. 为什么不用 Redis 存这些数据?
参考回答:Redis 可以实现许多缓存场景,但大块 KV 的瓶颈可能在复制、协议、CPU、网络栈和 GPU 数据路径。Mooncake 面向大对象资源池、registered buffer、RDMA/多网卡等路径优化。要比较同样语义、对象大小、并发、容量和硬件,不能无条件宣称任何系统始终更快。
Q23. RDMA、零拷贝、GDR 分别是什么?
参考回答:RDMA 支持 NIC 直接访问已注册内存,减少远端 CPU 数据搬运;零拷贝描述某个边界避免了复制;GDR 允许支持的平台把 GPU 内存作为直接访问对象。它们不自动省掉 Python 拷贝、布局转换、GPU 同步、控制面 CPU 和所有中间 buffer。
Q24. 为什么注册内存很贵,如何优化?
参考回答:注册涉及内存映射、页处理和 NIC 资源,频繁注册小 buffer 会把固定成本放大。可用长期预注册内存池和批操作摊薄成本,但需控制 pinned memory、memlock、碎片和资源占用,并在所有在途操作结束后才能注销。
Q25. 异步传输超时后可以马上 free buffer 吗?
参考回答:不能仅凭调用方超时就释放。必须确认底层已完成、取消成功并 drain,或有明确机制保证 NIC/worker 不再访问。输入/输出 buffer、Python owner、GPU tensor、MR 和请求对象的生命周期都要覆盖真正的在途阶段。
Q26. 多网卡为什么没有线性扩展?
参考回答:可能受 PCIe/NUMA/内存带宽、共享上联、目标热点或软件轮询限制;慢 rail 也会拖累大请求尾部。需要测单路径、聚合路径和不同 NUMA,检查实际有效 payload 带宽及 P99。不能把多 NIC 名义线速直接相加当实际结果。
Q27. Batch API 是事务吗?如何处理部分失败?
参考回答:Batch 主要摊薄 RPC、锁和提交开销,一般不应假设 all-or-nothing。检查逐项结果,只重试可安全重试的项;同键幂等和内容一致性要独立设计。过大 batch 会延长首个结果等待、增加在途内存和长尾,需要测量合适粒度。
三、LMCache 与集成:Q28–Q39
Q28. LMCache 和 Mooncake 是竞争关系吗?
参考回答:在常见组合里职责互补。LMCache 管推理相关 KV 查找、分层和保存/加载,Mooncake 作为共享对象后端和传输基础设施;也可以通过原生 Connector 直接使用 Store。选型要先明确是需要 KV 管理能力、共享池,还是仅需要 PD 字节交接。
Q29. LMCache MP 与旧版有什么区别?
参考回答:MP 把缓存服务放到独立进程,用 Connector 与引擎协作,L1 Manager 管活动缓存,Store/Prefetch controllers 协调 L2 adapter;旧版常见 LMCacheEngine/StorageManager/RemoteConnector。配置、native 扩展与进程生命周期不同,不能混用两套启动参数。MP 有独立管理的好处,也增加 IPC、锁和服务协调成本。
Q30. 为什么 LMCache MP 的 L1 与 HiCache 的 L1 不同?
参考回答:层级是各框架的命名。HiCache 通常将 GPU/CPU/外部存储称为 L1/L2/L3;LMCache MP 的常见配置将 CPU 活动缓存称为 L1、外部后端称为 L2,GPU 位于引擎侧。讨论时直接说 GPU、主机内存、远端 Store,避免只说层号。
Q31. LMCache lookup 命中后就可以跳过 prefill 吗?
参考回答:还不够。需要确认对象从后端成功加载、目标 GPU block 准备好、布局兼容、同步完成,并且各 TP rank 认可相同的有效连续前缀。lookup 和真正可消费之间可能发生淘汰、超时或目标空间不足。
Q32. P/D 分离必须经过 Mooncake Store 吗?
参考回答:不必须。可以用直接 TE Connector 交接 KV,也可以采用 Store 或 LMCache 支持的对象存储交接。直接路径适合明确的当前消费者;Store 提供复用与资源池能力,但增加对象管理和可能的中间层开销。共享缓存也可以用于未做 PD 分离的实例。
Q33. 如何避免 Prefill 写未完成,Decode 就开始读?
参考回答:定义明确的数据 ready 协议,区分 GPU 生产完成、缓存本地可见、远端可读和消费者 GPU 就绪。上层 telemetry/通知与 Store 完成状态结合,Decode 只使用已完成且兼容的状态;超时后有界等待或降级。单个函数返回、单个网络 completion 不必然代表所有 rank 和 GPU 消费都已就绪。
Q34. 为什么需要 layer-wise 或分块流水线?
参考回答:让计算、传输、加载有机会重叠,减少关键路径等待。但更细粒度增加任务、事件和元数据开销,必须证明消费者使用每层时相应 KV 已到达,并保留 buffer 生命周期。最优粒度依赖模型、布局和链路,不是越细越好。
Q35. Chunk 越大越好吗?
参考回答:大 chunk 能摊薄固定开销、提高带宽,小 chunk 能减少多取数据并扩大部分复用机会。还要考虑引擎 page 对齐、TP/layout、每对象元数据、尾部浪费和预取 deadline。应扫描 chunk 大小,比较最终 goodput,而不是只看带宽。
Q36. 多 TP ranks 命中长度不一样怎么办?
参考回答:消费前必须对有效可用前缀达成一致,常见做法是取各 rank 最小成功长度,剩余部分继续计算。不能让某个 rank 使用尚未准备好的 shard。跨 TP 配置共享更复杂,需要显式重分片、布局转换和兼容性检查。
Q37. CacheBlend 如何复用非前缀文档?
参考回答:利用缓存片段并选择性重算部分 token,处理新上下文下跨片段 attention 的影响;具体算法和支持条件随版本而异。它不是简单拼接对象就能保证无损,需要同时评估速度与任务质量。普通精确 prefix caching 与这种复用的保证不同。
Q38. 多模型与多租户共用 Store 要注意什么?
参考回答:将模型 revision、adapter、layout 等纳入兼容性 namespace,按租户/共享组隔离并设置配额与调度公平性。cache salt 影响复用域,但不能替代认证授权;同名模型路径也可能是不同权重。还要考虑命中时间侧信道和错误清理范围。
Q39. Conductor 提供什么价值,索引过期会怎样?
参考回答:它消费缓存事件形成全局前缀位置视图,帮助路由预测在哪个实例和 tier 可复用。事件可能延迟或丢失,因此索引是调度提示,实际读取仍需 Store/引擎验证。过期索引应最多造成性能损失或回退,不能导致消费不兼容或不可用数据。
四、性能、可靠性与系统设计:Q40–Q50
Q40. 什么时候拉取 KV 比重新计算更慢?
参考回答:比较查询、关键路径搬运、布局/同步和新增排队成本,与可以省下的 prefill 时间。短 prefix、低带宽、远端拥塞、大 KV/低计算比、GPU 可立即计算或目标 buffer 紧张时,重算可能更好。预取可隐藏部分开销,但要根据实际重叠而非理论峰值计算。
数量级:1 GiB 在 20 GiB/s 下仅网络就需约 50 ms;不能把“几毫秒的 lookup”当作完整加载成本。
Q41. 命中率升高但 TTFT/ITL 变差,你怎么排查?
参考回答:确认命中层与成功加载前缀,再分解 queue、lookup、fetch、H2D/layout、prefill 和 handoff。检查后台写入/预取是否争抢 NIC、PCIe、CPU 或 GPU copy,检查热点与跨 rank 等待。用 local-only、remote-cold、remote-warm、combined 消融定位,不一次改很多参数。
Q42. 什么缓存淘汰策略适合 KV?
参考回答:先排除在途、租约有效和不可淘汰对象,再在候选中考虑最近访问、频率、体积与重算收益。LRU 易实现但会被一次性长文本扫描污染;频率准入或收益/字节估计可以保护热点,却需要更多统计和适应机制。通用策略建议要与 Mooncake 当前近似 LRU 实现分开表述。
Q43. 如何处理热点和缓存击穿?
参考回答:热点读取可通过本地缓存、热点副本、路由分散和限流缓解;缺失时多个相同前缀同时重算可用 singleflight/在途请求合并。等待要有 deadline,owner 失败后需要恢复,不能无限阻塞。副本和合并状态都有容量及协调成本。
Q44. 如何估算集群存储与网络规模?
参考回答:容量按新增唯一 KV 速率、保留时间、每 token 字节数、副本数和可用水位估算;网络按实际远程读、复制写、PD、预取和重平衡分别统计。元数据按对象数与每对象/副本开销估算,不只看 payload。工作集复用、TP 分片和所有权会改变实际数量级。
Q45. Master HA 能保证 KV 数据不丢吗?
参考回答:Master HA 恢复控制面元数据与服务可用性,不能重建全部已经丢失的 DRAM payload。还需要数据副本或可靠冷层,并在恢复后验证 descriptor、资源存活和对象完成状态。缓存允许丢失后重算,但不能返回错误数据。
Q46. 如何设计过载保护?
参考回答:同时限制计算、缓存读取、写回和在途 buffer;根据 TTFT 与 Decode SLO 估计排队预算,进行有界排队、准入或拒绝。背压不能只堆在某个后台队列,失败重试也要有预算和抖动。报告 offered load、拒绝与 goodput,避免靠丢请求制造低延迟。
Q47. 分布式缓存需要像数据库那样强一致和持久化吗?
参考回答:需求不同,但缓存也必须有足够强的对象正确性:不能读到部分提交、已回收或错误版本的 KV。数据丢失可重算时,持久性要求可放松,但对象可见性、并发删除和生命周期不能随便放松。不可变内容键能简化协调,不能消除所有分布式故障。
Q48. 如何验证缓存真的提升吞吐?
参考回答:固定硬件、模型、输入输出长度、到达分布和 SLO,比较无复用、本地复用、外部冷/热缓存的 goodput。检查成功/拒绝/超时与尾延迟,确认真正减少了 prefill。报告多次运行波动、有效网络字节与 CPU/GPU 代价,不只展示重复一个 prompt 的最优图。
Q49. 用 5 分钟设计一个 KV Cache 存储服务。
参考回答:先确认模型、工作集、复用率、SLO 与故障假设,算容量/带宽/对象数。分离对象控制面和数据面,用版本化内容键、分层缓存、明确写提交和读保护协议;按负载选择副本、准入与预取。缓存失效有重算路径,路由结合位置与队列,监控从对象错误到用户 goodput。最后指出最可能的两个瓶颈并设计实验验证。
完整数值案例见 系统设计,不要直接把答案里的假设当成面试官的实际需求。
Q50. 如何介绍你的学习项目,体现深度?
参考回答模板:“我在固定版本和硬件上,对某模型做了 local-only、remote-cold、remote-warm 对照。先验证内容/输出和命中来源,再分解 TTFT,发现主要瓶颈是 X。修改 Y 后,指标 Z 在明确的样本量与 SLO 下变化,同时代价是 W。我还复现了一种失败,验证读取失败后不会消费错误 buffer。尚未覆盖的边界是……”
没有硬件实测时改为“源码分析与 TCP/模拟验证”,用明确证据展示能力。不要编造吞吐提升、生产规模或线上故障经历。
模拟面试组织
第一轮 30 分钟:Q3 容量计算、Q16/Q18 读写、Q23/Q25 通信、Q28/Q31 集成、Q40 收益模型。第二轮 45 分钟:Q49 系统设计,加 Q41/Q43/Q45 的故障追问。
评分关注四项:事实是否准确、假设是否完整、能否说明代价、是否有源码或实验支持。回答里的任何数字都应能追溯到公式或原始测量。