1.应用与现象
Redis用作缓存是一种非常常见的方法,但是这可能导致缓存数据和数据库数据不一致的问题,例如:下面我通过redis工具栏让该方法的数据进入redis缓存
它的第一次查询结果是:
接下来我直接修改该条数据为:
我再次刷新页面后的查询结果还是:
这就造成了数据不一致问题,那怎么解决呢?
接下来我将介绍两种方法
2.解决方法
2.1延迟双删
在缓存一致性问题的解决方案中,延时双删策略(Delayed Double Deletion)是一种常见的方法。它通过在数据库更新后先删除缓存,然后在短时间延迟后再次删除缓存,来解决缓存与数据库之间的潜在数据不一致问题。
延时双删策略的步骤:
1.删除缓存:首先删除缓存中的数据。
2.更新数据库:接着更新数据库中的数据。
3.延时再删:等待一段时间后,再次删除缓存,以防止并发写导致的数据不一致问题。
将我的更新代码改成上述的延迟双删后:
@Override
public ResponseResult updateGoods(TGoodsEntity goods) {
String cacheKey = "goods";
// Step 1: 立即删除缓存
evictCacheImmediately(cacheKey);
// Step 2: 更新数据库
int i = tGoodsMapper.updateGoods(goods);
if (i > 0) {
// Step 3: 延时后再次删除缓存
evictCacheWithDelay(cacheKey);
return ResponseResult.success("修改成功");
}
return ResponseResult.error(AppHttpCodeEnum.UPDATE_FAIL);
}
// 立即删除缓存的方法
public void evictCacheImmediately(String cacheKey) {
redisUtils.delete(cacheKey);
System.out.println("立即删除缓存: goods::" + cacheKey);
}
// 延时再删缓存的方法
@Async
public void evictCacheWithDelay(String cacheKey) {
scheduler.schedule(() -> {
System.out.println("延时删除缓存: goods::" + cacheKey);
evictCacheImmediately(cacheKey);
}, 5, TimeUnit.SECONDS); // 延时5秒,可以根据具体情况调整
}
再次执行更新方法后,查询结果为:
这就实现了缓存数据一致了。
2.2 Canal + MQ解决存数据一致性问题
缓存与数据库的数据一致性问题,是分布式系统中一个常见且复杂的挑战。使用 Canal 和消息队列(MQ),是一种非常有效的方式来确保缓存与数据库之间的数据一致性。
2.2.1什么是Canal
Canal 是阿里巴巴开源的一个 MySQL binlog 增量订阅和消费组件。它可以模拟 MySQL 主从复制的过程,从而读取主库的 binlog,实时地监控和捕获数据变更。这样就可以将数据库的更新实时同步到其他系统或缓存中。
2.2.2什么是MQ
消息队列(MQ)是一种异步通信协议,允许系统之间通过队列传递消息。常见的 MQ 实现有 RabbitMQ、Kafka、ActiveMQ 等。MQ 可以用来实现数据的异步处理和分布式事务的协调。
流程概述:
1.Canal 监听数据库变更:
Canal 连接到 MySQL 数据库,模拟从库,订阅 binlog 日志,实时捕获数据库的增、删、改操作。
2.Canal 将变更数据推送到 MQ:
捕获到的数据库变更事件(如 insert、update、delete)被 Canal 推送到消息队列中。
3.消费 MQ 消息并更新缓存:
一个消费者(或者多个消费者)订阅 MQ 的消息,获取到变更事件后,根据事件的类型和内容,更新缓存中的对应数据。