14人参与 • 2026-04-30 • Redis
这篇聊一个很现实的问题:数据库已经改成功了,但缓存删除失败了,线上怎么办?
如果你项目里只有一句 redis.del(key),那一致性是靠运气。
一套更稳的做法是:
一句话:删除缓存不是一个动作,而是一条可观测、可补偿的链路。
很多同学会说:“删失败就下次再读库呗。”
这句话在低并发时看起来没毛病,但线上高峰期会出事:
最麻烦的是:这个问题不会立刻报错,而是以“偶发投诉”“数据不对”的形式出现,排查成本很高。

你会发现,核心不是“怎么删”,而是“删不掉时怎么兜”。
@service
public class productservice {
@resource
private productmapper productmapper;
@resource
private stringredistemplate redistemplate;
@resource
private cachedeleteproducer cachedeleteproducer;
@transactional(rollbackfor = exception.class)
public void updateproduct(product product) {
string key = "product:" + product.getid();
// 1) 数据库是事实来源
productmapper.updatebyid(product);
// 2) 主流程删缓存,失败则入重试队列
try {
redistemplate.delete(key);
} catch (exception ex) {
cachedeleteproducer.senddeleteevent(key, 1);
}
}
}@component
public class cachedeleteconsumer {
private static final int max_retry = 5;
@resource
private stringredistemplate redistemplate;
@resource
private cachedeleteproducer cachedeleteproducer;
@resource
private deadletterproducer deadletterproducer;
public void onmessage(cachedeleteevent event) {
try {
redistemplate.delete(event.getcachekey());
// 打点:delete_success_total +1
} catch (exception ex) {
int nextretry = event.getretrycount() + 1;
if (nextretry > max_retry) {
deadletterproducer.send(event.getcachekey(), ex.getmessage());
return;
}
long delayseconds = (long) math.pow(2, nextretry); // 2,4,8,16,32
cachedeleteproducer.senddeleteevent(event.getcachekey(), nextretry, delayseconds);
}
}
}@component
public class cachedeletecompensationjob {
@resource
private deadletterrepository deadletterrepository;
@resource
private stringredistemplate redistemplate;
// 每 5 分钟跑一次
@scheduled(cron = "0 */5 * * * ?")
public void compensate() {
list<deadletterrecord> records = deadletterrepository.queryunresolved(200);
for (deadletterrecord record : records) {
try {
redistemplate.delete(record.getcachekey());
deadletterrepository.markresolved(record.getid());
} catch (exception e) {
deadletterrepository.increasefailcount(record.getid(), e.getmessage());
}
}
}
}幂等性
删缓存天生幂等,删不存在 key 也算成功,别把它当异常。
重试上限
不要无限重试,超过阈值必须死信,不然就是隐性消息堆积。
退避策略
固定 1 秒重试容易打爆 redis,用指数退避更稳。
死信可见性
死信不等于丢弃,要有告警和处理面板。
链路监控
至少要有这几个指标:
cache_delete_fail_totalcache_delete_retry_totalcache_delete_dlt_totalcache_delete_compensation_success_total线上你总会遇到:网络抖动、redis 短暂超时、连接池耗尽。
低概率 * 高频请求 = 可观事故数。
延迟双删只能覆盖一部分并发窗口,无法替代失败重试链路。
只靠人工盯死信,夜里一定会漏。
最好是“告警 + 自动补偿 + 人工兜底”三层。
| 团队阶段 | 推荐方案 |
|---|---|
| 小团队、单体服务 | 写库后删缓存 + 本地重试(短期) |
| 中型团队、多服务 | 写库后删缓存 + mq 重试 + 死信告警 |
| 大团队、高一致性要求 | 事件驱动一致性 + 死信平台 + 自动补偿任务 |
“删除缓存失败”不是小概率边角料,它是缓存一致性的主战场。
真正能扛线上流量的方案,通常长这样:
把这四件事做到位,你的缓存一致性就不是“玄学”,而是工程能力。
以上就是redis删除缓存失败的原因和解决方案的详细内容,更多关于redis删除缓存失败的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论