设计一个支持百万 QPS 的分布式缓存系统。
未标记
考查重点:热点分布与容量验证。先定读写、值大小与热点,分片和多级缓存承载普通流量,热点复制与回源保护抗峰值;容量由真实压测推算
本题目录
参考答案
核心回答
百万 QPS 先是负载目标,不是节点数量。要先明确读写比例、值大小、热点分布、一致性要求、命中率和延迟目标,再设计分片、多级缓存和回源保护。不能用一台机器的理想 GET 成绩直接除算集群规模。
先算容量,再选访问路径
例如每次返回 1 KiB,百万次读每秒仅有效载荷就约为 1 GB/s,还没有协议、复制和网络开销。容量规划至少同时估算 CPU、网络、内存、连接、复制和持久化成本。节点吞吐应来自接近真实命令、包体与热点的压测,并预留故障和流量波动余量。
常见路径是进程内热点缓存、分布式缓存、事实存储逐级访问。本地缓存减少网络请求,但多实例之间需要 TTL、版本或失效通知策略;其一致性窗口应由业务接受。分布式层可采用 Redis Cluster 等分片方案,让不同 Key 分布到不同分片,副本用于容灾或在允许陈旧读时分担读压力。
热点和回源怎样保护
单个热点 Key 仍由一个槽的主节点处理,增加分片无法自然拆开这个 Key。读热点可以用本地缓存、请求合并或合理的数据副本;写热点则需要按业务语义拆分,例如可延迟汇总的计数分片,不能直接套用到必须严格扣减的库存。
回源要有并发上限和隔离,防止一个分片故障或大量 Key 同时过期把数据库击穿。可结合随机 TTL、热点预热、单飞重建、负缓存,以及适合场景的布隆过滤器;每一种措施都要处理陈旧数据或误判边界。限流、降级和有限重试应覆盖故障链路。
容量淘汰与一致性
如果要求自动淘汰最久未使用项,要先明确是每分片近似 LRU,还是严格全局 LRU。后者需要协调访问顺序,代价很高;Redis 使用采样近似 LRU,并非全局精确双向链表。内存预算还需给复制缓冲、碎片和运行开销留空间。
写入通常以事实存储为准,再更新或失效缓存;通过版本、事件和对账处理异常窗口。缓存丢失后的正确性不能依赖“缓存里一定有值”。
如何证明达到目标
分别验证稳定流量、偏斜热点、冷启动、扩缩容、节点失效和回源受限。除了总 QPS,还应看 P95/P99、错误率、命中率、每分片负载、网络带宽、淘汰率和数据库压力。只有同时满足正确性、延迟与故障目标,百万 QPS 才是有意义的结果。
参考资料
- 国内:JavaGuide / Snailclimb:缓存基础常见面试题:借鉴多级缓存与通知的讨论,解释正文中本地缓存如何降低远程压力,以及多实例失效通知的一致性窗口。
- 国内:JavaGuide / Snailclimb:Redis 常见问题(下):热点与回源:热点章节区分多个热 Key 和单个热 Key,解释扩分片为何不能解决所有吞吐瓶颈。
- 国内:小林 coding:为什么要有 Redis Cluster 集群:参考槽到节点的映射,说明正文中横向分片分散不同 Key、允许陈旧读时副本分担读流量的条件。
- 国外:Redis:Key eviction:依据内存与采样 LRU 的说明,解释正文中容量预算、近似局部淘汰与严格全局 LRU 的区别。
- 国外:Microsoft:Cache-Aside pattern:借鉴旁路缓存的故障与一致性分析,组织正文中未命中回源保护及事实存储更新后的缓存失效流程。
