题目重点:设计持久键值服务,明确强一致或最终一致合同、热点键、版本冲突与扩容。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练接口get/put/delete,key/value大小上限、TTL、读写比需先问;这里以单key线性一致、无跨key事务为主方案。
- 持久化与缓存是不同要求。缓存失效可以回源,持久KV若丢最后ACK的数据会违背合同。
- 容量例10亿key,平均key32B/value1KB,原始约1.06TB,三副本约3.2TB下限,另计索引/WAL/碎片与历史。
解题路线
- 路由按hash-range或虚拟节点分片,每shard选leader并复制持久日志;写ACK需满足承诺的复制/落盘策略。版本按leaderEpoch+logIndex生成,旧leader通过fencing禁止写入。
- 强一致读取走leader或经证实可读的readIndex/lease,不简单读任意副本。若选择quorum最终一致版本,则解释并发写版本、合并和read repair;R+W>N不是自动线性一致证明。
- 删除写tombstone,传播与GC必须保证旧副本不能把旧值复活。TTL使用权威过期语义,读时判断,后台回收负责空间而非可见性。
- 扩容迁移先快照复制,再追日志增量,达到cutover水位后用路由epoch切换。旧路由forward或拒绝而不是同时接受独立写,保证单key只有一条权威顺序。
- 热键读缓存、singleflight与副本分担;热键写不能靠hash拆开保持同一语义,可在业务允许时把计数操作分桶聚合。过大value放对象存储并用版本引用避免日志拥塞。
手动走一遍
put(k,A)在epoch4确认,网络分区后epoch5leader写B;旧leader恢复收到put(k,C),必须拒绝旧epoch写,不能随后把C推回。删除k后长期离线副本的A不能越过删除墓碑复活。
规模与取舍
本地查找按hash为预期O(1)或LSM读放大;端到端延迟取决于副本跨区RTT、WALfsync与排队。迁移持续吞吐必须超过新写增量才能追上,不能只估快照大小。
易错点与追问
容易失分的边界
- consistent hashing解决路由变化,不直接解决复制与一致性。
- 只说CAP选CP无法交代失败时get/put具体行为和超时重试语义。
- 无限重试写请求会重复执行非幂等操作,requestId和条件版本需协议内。
继续深挖
- 最终一致模式如何定义同一key并发更新?LWW容易丢信息,可版本向量/CRDT但必须匹配值的数据类型。
- 若某shard磁盘坏而日志在其余副本,恢复流程如何验证完整性并避免让落后副本成为leader?
