详情

首页手游攻略 高并发系统中缓存更新到底是先删缓存还是先更新数据库实用指南

高并发系统中缓存更新到底是先删缓存还是先更新数据库实用指南

佚名 2026-10-23 19:30:02

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“高并发系统中缓存更新到底是先删缓存还是先更新数据库”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

一、为什么会有一致性问题

结合项目来看,在高同时发系统里,数据库通常作为最后数据源,Redis 作为缓存层提升查询性能。典型读流程是:先查缓存,缓存未命中再查数据库,并把结果写入缓存。

从实现思路看,问题出现在写请求上。数据库和缓存是两个独立组件,更新操作无法天然保证原子性。只要其中一步失败,或者同时发读写交错,就可能出现缓存和数据库数据不一致。

二、两种更新策略

1.先删除缓存,再更新数据库

从实现思路看,当线程 1 先删除缓存后,如果在更新数据库的时候阻塞住了,这个时候线程 2 先去读缓存,缓存不存在,随后去数据库中读取数据,读到数据后重建缓存,这个时候缓存中仍然是旧的数据。

所以这种方案一般不建议。(解决方案看后续的延迟双删模块)

2. 先更新数据库,再删除缓存

实际处理时,这种方案看起来更加合理一些。但是可能会出现短暂的数据不一致,导致读到旧的缓存。不过这种情况一般都是能够接受的,能够保证最后的一致性。

三、延迟双删:解决先删缓存的问题

采用延迟双删缓解解决先删缓存存在的问题。

删除缓存 -> 更新数据库 -> 延迟一段时间 -> 再次删除缓存

第二次删除是为了解决重建的缓存是旧的数据。

为什么要进行延迟删除?

理解这一步时,延迟删除的目的是为了防止出现线程 2 还没来得及进行旧数据缓存的重建,导致删除是空的缓存,旧的数据缓存还是被重建了这种情况。但是延迟的时间一般是不太好控制的。

实际处理时,延迟双删保证了最后一致性,解决了重建的是旧数据缓存,请求拿到的是旧的数据的问题。

四、MQ 补偿:解决删除缓存失败

结合项目来看,无论是先删除缓存还是先更新数据库,都有可能出现删除缓存失败的情况,为了解决删除缓存失败,能够采用 MQ 做补偿。

更新数据库
删除缓存
如果删除失败,发送 MQ 消息
消费者异步重试删除缓存
多次失败后记录日志/告警

示例伪代码:

public void updateData(Data data) {
    updateDatabase(data);

    try {
        redis.delete(cacheKey);
    } catch (Exception e) {
        mq.send(new CacheDeleteMessage(cacheKey));
    }
}

消费者

public void consume(CacheDeleteMessage message) {
    redis.delete(message.getKey());
}

六、Canal:进一步解耦业务和缓存删除

结合项目来看,MQ 补偿虽然能解决失败重试,但业务代码里还是要写删除缓存或发送消息的逻辑。为了进一步解耦,能够采用 Canal MySQL binlog。

业务只更新 MySQL
MySQL 产生 binlog
Canal binlog
解析变更表和主键
发送缓存删除消息
消费者删除 Redis

优点:

  • 业务代码不需关心缓存删除
  • 多个服务修改同一张表,也能统一
  • 缓存失效逻辑集中处理
  • 更适合复杂系统

总结

实际处理时,缓存一致性的关键不是追求绝对强一致,而是明确数据库是最后事实来源,缓存是可丢弃的加速层,借助删除缓存、失败重试、TTL 和 binlog 等方式保证最后一致。

相关资讯
点击查看更多
游戏推荐
推荐专题
热门阅读
推荐下载