先更新db还是先更新缓存

  1. 先删除缓存 ,再更新db
  2. 先更新db,再删除缓存
    • 旧值,脏数据问题 (可能会读到缓存旧值,只能保证最终一致性)
  3. 删除缓存,更新db,延迟删除缓存 (双删除策略)

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

先删除缓存, 多线程访问的情况下,会有数据不一致性

先删除缓存

  1. 高并发的情况下,会有缓存击穿的问题
  2. 并发查询的时候,旧值可能重写会缓存

更新数据库,再更新缓存

后删除缓存问题

双删除策略

双删除策略

仅仅进行一次删除缓存的操作可能并不足够。因为在多线程或高并发的环境下,可能会出现这样的问题:一个线程更新了数据库并删除了缓存,但在它删除缓存之前,另一个线程已经读取了旧的缓存数据。如果这个线程在第一个线程删除缓存之后才更新缓存,那么就会导致缓存中的数据仍然是旧的、不一致的。

需要注意的是,双删除缓存策略并不能完全解决所有并发问题。在某些极端情况下,仍然可能会出现数据不一致的情况。因此,在设计和实现分布式系统时,还需要结合其他技术手段(如分布式锁、消息队列等)来进一步提高数据的一致性和可靠性。

这种双删除缓存策略的区别在于它提高了数据一致性的保障程度。通过两次删除缓存的操作,它降低了在并发环境下出现数据不一致的风险。当然,这也带来了一定的性能开销,因为每次更新数据库都需要执行两次删除缓存的操作。但是,在需要保证数据一致性的场景中,这种开销通常是值得的。

删除缓存教程

https://zhuanlan.zhihu.com/p/467410359

延时双删用比较简洁的方式实现 mysql 和 redis 数据最终一致性,但它不是强一致。 延时,是因为 mysql 和 redis 主从节点数据同步不是实时的,所以需要等待一段时间,去增强它们的数据一致性。 延时 是指当前请求逻辑处理延时,而不是当前线程或进程睡眠延时。 mysql 和 redis 数据一致性是一个复杂的课题,通常是多种策略同时使用,例如:延时双删、redis 过期淘汰、通过路由策略串行处理同类型数据、分布式锁等等。

延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再sleep一段时间,然后再次删除缓存。

sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。

流程如下:

  1. 线程1删除缓存,然后去更新数据库
  2. 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存
  3. 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除
  4. 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值

如果反过来操作,先更新数据库,再删除缓存呢?

这个就更明显的问题了,更新数据库成功,如果删除缓存失败或者还没有来得及删除,那么,其他线程从缓存中读取到的就是旧值,还是会发生不一致。

其他解决方案

消息队列 这是网上很多文章里都有写过的方案。但是这个方案的缺陷会更明显一点。

先更新数据库,成功后往消息队列发消息,消费到消息后再删除缓存,借助消息队列的重试机制来实现,达到最终一致性的效果。

这个解决方案其实问题更多。

引入消息中间件之后,问题更复杂了,怎么保证消息不丢失更麻烦 就算更新数据库和删除缓存都没有发生问题,消息的延迟也会带来短暂的不一致性,不过这个延迟相对来说还是可以接受的

延时双删只是增加了一次redis的key的操作,消耗基本可以忽略不计!建议用延时双删!

以下是使用场景区别: 1.先改数据库再改缓存:对接口速度有要求,确保修改数据能在最短时间内同步的情况使用,以为它比延迟双删少了一次耗时计算和key操作。 使用场景如 :任务部门操作同步延迟、常用模板生效时间延迟、监控人员坐标位置信息最快时间展示等

2.延时双删:可以接受一定延迟,并且一致性要求比较强的时候使用延时双删,延时双删,只是降低了同步不及时概率,并不是强一致性,延时时间是一个预估值,不能确保 mysql 和 redis 数据在这个时间段内都实时同步或持久化成功了 使用场景 如:基础数据平台提供数据给其他系统使用,要求数据及时同步,并且这个接口不会被频繁调用

canel 是什么

https://blog.csdn.net/qq_42956993/article/details/128974247

为什么要用 canel, 而不是 更新数据库的时候删除缓存?

如果删除缓存的时候 会有一段时间热点key请求打到数据库, 产生缓存击穿

所以 我们可以用 canel组件, mysql更新时候,被canel捕获到,立刻更新到redis上。

https://github.com/alibaba/canal

阿里巴巴 MySQL binlog 增量订阅&消费组件

早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

基于日志增量订阅和消费的业务包括

数据库镜像 数据库实时备份 索引构建和实时维护(拆分异构索引、倒排索引等) 业务 cache 刷新 带业务逻辑的增量数据处理 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

canel用法

可以用来订阅 MySQL更新记录,比如写入kafaka,hbase,redis 等工具

用于实现双写一致性

双写一致性的两种情况

  1. redis有数据 – 需要和数据库值相同
  2. redis无有数据 – 用数据库的最新值