一、一致性分级与适用场景
级别 | 延迟范围 | 适用场景 | 代表方案 |
---|---|---|---|
强一致性 | 0ms | 金融账户、库存扣减 | 分布式锁+同步双写 |
最终一致性 | 10ms-10s | 商品详情、用户信息 | 延迟双删、消息队列 |
弱一致性 | >10s | 文章阅读量、排行榜 | 定时全量刷新 |
二、经典解决方案详解
1. Cache-Aside Pattern(旁路缓存)
流程:
App Cache DB 读请求 返回数据 查询数据 返回数据 写入缓存 alt [缓存命中] [未命中] 写数据 删除缓存 App Cache DB
问题 :先写库后删缓存的间隙可能读到旧数据
优化:异步延迟双删(解决并发读写脏数据)
2. Write-Through(穿透写)
架构:
应用 Cache Write Handler DB
- 所有写请求先到Cache,由Cache同步写DB
- 优点:确保缓存永不过期
- 缺点:写延迟高(需等待DB完成)
3. Write-Behind(异步写)
流程:
App Cache DB 写数据 立即响应 批量写回 loop [异步批处理] App Cache DB
特点:
- 高性能(写操作≈内存速度)
- 数据可能丢失(宕机时缓存未刷盘)
- 需配合WAL日志(如Redis AOF)
三、高并发场景下的精控方案
4. 分布式锁强一致
java
// Redisson实现示例
public void updateData(Data newData) {
RLock lock = redisson.getLock("DATA_LOCK:" + newData.id);
try {
lock.lock(); // 获取分布式锁
db.update(newData); // 更新数据库
cache.delete(newData.id); // 删除缓存
} finally {
lock.unlock();
}
}
缺陷:性能下降(吞吐量≈DB单点写入能力)
5. 版本号控制(乐观锁)
操作步骤:
-
数据中增加版本号字段
version
-
更新时校验版本号:
sqlUPDATE table SET value=#{value}, version=version+1 WHERE id=#{id} AND version=#{oldVersion}
-
若更新失败,重试或回滚缓存
6. Binlog监听同步(最终一致)
Binlog 消息 MySQL Canal RocketMQ 缓存更新Worker Redis
优势:
- 彻底解耦应用层
- 支持多级缓存同步
时延:100ms-2s(取决于MQ堆积)
四、特殊问题解决方案
7. 缓存删除失败补偿机制
失败 成功 失败 删除缓存 记录删除失败Key 定时任务 读取失败队列 重试删除 移除队列 报警+人工介入
关键参数:
- 首次重试:1s后
- 指数退避:最大重试5次
- 死信处理:NACK后持久化存储
8. 热点Key并发重建
问题 :缓存失效瞬间大量请求击穿DB
解法:
java
// 使用Redis SETNX 互斥锁
public Data getData(String key) {
Data data = cache.get(key);
if (data == null) {
String lockKey = "LOCK:" + key;
if (redis.setnx(lockKey, 1)) { // 获取锁
redis.expire(lockKey, 3); // 避免死锁
data = db.query(key); // 查库
cache.set(key, data, 30); // 写缓存
redis.del(lockKey); // 释放锁
} else {
Thread.sleep(50); // 等待后重试
return getData(key); // 递归调用
}
}
return data;
}
五、方案选型决策树
graph TD
A[业务要求强一致?] -->|是| B[分布式锁]
A -->|否| C{写频率}
C -->|高频写| D[Write-Behind+WAL]
C -->|低频写| E[Cache-Aside+延迟双删]
C -->|批量写| F[Binlog监听]
六、工业级配置参数参考
组件 | 关键配置项 | 推荐值 | 作用 |
---|---|---|---|
Redis | maxmemory-policy | volatile-lfu | 内存淘汰策略 |
Canal | canal.mq.retries | 5 | MQ发送重试次数 |
Redisson | lockWatchdogTimeout | 30000 | 看门狗超时(ms) |
本地缓存 | Caffeine.expireAfterWrite | 5s | 防雪崩时间窗口 |
七、容灾设计
-
降级开关
java// 配置中心动态开关 if (ConfigService.getBool("DISABLE_CACHE")) { return db.query(key); // 直接读库 }
-
缓存污染防护
- 空值缓存:
SET key null 5s
防穿透 - 布隆过滤器:拦截非法Key请求
- 空值缓存:
-
多级熔断
指标 阈值 动作 DB QPS >5000 关闭缓存更新 缓存Miss率 >40% 开启本地缓存 平均响应时间 >200ms 跳过缓存直读DB
你想要的我全都有:https://pan.q删掉憨子uark.cn/s/75a5a07b45a2
