题目
设计支持千万级QPS的电商商品详情页缓存系统
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
分布式缓存架构设计, 缓存一致性策略, 缓存穿透/击穿/雪崩解决方案, 高可用与容灾设计, 性能优化
快速回答
核心设计要点:
- 多级缓存架构:本地缓存+分布式缓存+热点探测
- 缓存更新策略:Write-Behind + TTL续期 + 延迟双删
- 防雪崩机制:随机过期时间 + 熔断降级 + 热点Key分片
- 防穿透方案:布隆过滤器 + 空值缓存
- 高可用设计:集群分片+主从复制+异地多活
1. 系统架构设计
多级缓存架构:
- L1:本地缓存(Caffeine/Guava),命中率80%
- L2:分布式缓存(Redis Cluster),存储全量数据
- L3:持久化存储(MySQL分库分表+Elasticsearch)
- 热点探测:实时监控QPS,对热点Key进行本地缓存预热
// 伪代码:多级缓存访问逻辑
public Product getProduct(String id) {
// 1. 查本地缓存
Product product = localCache.get(id);
if (product != null) return product;
// 2. 查分布式缓存
product = redis.get(id);
if (product != null) {
localCache.put(id, product); // 回填本地缓存
return product;
}
// 3. 防穿透:布隆过滤器校验
if (!bloomFilter.mightContain(id)) {
return null; // 肯定不存在
}
// 4. 查数据库(互斥锁防击穿)
Lock lock = lockMap.get(id);
lock.lock();
try {
product = db.get(id);
redis.setex(id, 300, product); // 设置随机TTL
if (product == null) redis.setex(id, 60, "NULL"); // 空值缓存
} finally {
lock.unlock();
}
return product;
}
2. 缓存一致性策略
Write-Behind模式:
- 写操作先更新数据库,异步更新缓存
- 使用消息队列保证最终一致性
- 结合延迟双删解决并发写问题:
1. 删除缓存 2. 更新数据库 3. 休眠500ms(取决于业务延迟) 4. 再次删除缓存
3. 异常场景处理
| 问题 | 解决方案 | 实现要点 |
|---|---|---|
| 缓存穿透 | 布隆过滤器+空值缓存 | 初始化全量Key到布隆过滤器,空值设置短TTL |
| 缓存击穿 | 互斥锁+热点永不过期 | 使用Redis SETNX实现分布式锁,热点Key后台续期 |
| 缓存雪崩 | 随机TTL+熔断降级 | 基础TTL=60min + 随机0-30min,Hystrix熔断DB访问 |
4. 高可用设计
Redis集群方案:
- 分片策略:采用CRC16分片(16384 slots)
- 主从复制:每个分片1主2从,哨兵自动故障转移
- 异地多活:同城双机房+异地灾备,使用Proxy路由
- 数据持久化:AOF每秒刷盘 + RDB每日备份
5. 性能优化
- 热点Key:
- 本地缓存分片:根据机器IP尾号做一致性哈希
- Redis分片再散列:对热点Key增加随机后缀(product_1234→product_1234_{0-9})
- 批量操作:Pipeline批量查询,减少网络往返
- 内存优化:使用Hash结构存储商品属性,ziplist压缩
6. 监控与治理
- 实时监控:缓存命中率、慢查询、内存使用率
- 动态配置:通过配置中心调整TTL、熔断阈值
- 压测方案:模拟秒杀场景,逐步放大流量验证
常见错误
- ❌ 双写时先更新数据库再更新缓存(导致脏数据)
- ❌ 使用固定TTL导致雪崩
- ❌ 热点Key集中到单分片
- ❌ 本地缓存无过期时间导致内存泄漏
扩展知识
- 新型方案:
- Redis 6.0多线程IO
- 持久内存方案:AEP+Redis
- CDN边缘缓存(适用于静态内容)
- 理论依据:
- 缓存淘汰策略:W-TinyLFU(Caffeine) vs LRU
- PACELC定理:分布式系统权衡