数据库与缓存双写时的数据一致性

原文:

https://www.cnblogs.com/mengchunchen/p/10065351.html

Cache Aside Pattern

  读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应

  更新的时候,先删除缓存,然后再更新数据库   (很多地方都说应该先更新数据库,再删缓存)

为什么是删除缓存,而不是更新缓存呢?

  原因很简单,很多时候,复杂点的缓存的场景,因为缓存有的时候,不简单是数据库中直接取出来的值

  比如可能更新了某个表的一个字段,然后其对应的缓存,是需要查询另外两个表的数据,并进行运算,才能计算出缓存最新的值的

  更新缓存的代价是很高的

  如果你频繁修改一个缓存涉及的多个表,那么这个缓存会被频繁的更新

  但是问题在于,这个缓存到底会不会被频繁访问到?

  举个例子,一个缓存涉及的表的字段,在1分钟内就修改了20次,或者是100次,那么缓存更新20次,100次; 但是这个缓存在1分钟内就被读取了1次,有大量的冷数据

  实际上,如果你只是删除缓存的话,那么1分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低

  每次数据过来,就只是删除缓存,然后修改数据库,如果这个缓存,在1分钟内只是被访问了1次,那么只有那1次,缓存是要被重新计算的,用缓存才去算缓存

  其实删除缓存,而不是更新缓存,就是一个lazy计算的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它到需要被使用的时候再重新计算

最初级的缓存不一致问题以及解决方案

  问题:先修改数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致

  解决思路:先删除缓存,再修改数据库,如果删除缓存成功,修改数据库失败,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致

  因为读的时候缓存没有,则读数据库中旧数据,然后更新到缓存中

 

比较复杂的数据不一致问题分析

  数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改

  一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中

  数据变更的程序完成了数据库的修改,此时缓存是旧数据,数据库是新数据

 

解决方案:更新与读取操作进行异步串行化

  更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个jvm内部的队列中

  读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个jvm内部的队列中

  一个队列对应一个工作线程

  每个工作线程串行拿到对应的操作,然后一条一条的执行

  这样的话,一个数据变更的操作,先执行,删除缓存,然后再去更新数据库,但是还没完成更新

  此时如果一个读请求过来,读到了空的缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成

  这里有一个优化点,一个队列中,其实多个更新缓存请求串在一起是没意义的,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可

  待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中

如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回; 如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值

方案一:

(1)更新数据库数据;
(2)缓存因为种种问题删除失败
(3)将需要删除的key发送至消息队列
(4)自己消费消息,获得需要删除的key
(5)继续重试删除操作,直到成功

然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。

方案二:

(1)更新数据库数据
(2)数据库会将操作信息写入binlog日志当中
(3)订阅程序提取出所需要的数据以及key
(4)另起一段非业务代码,获得该信息
(5)尝试删除缓存操作,发现删除失败
(6)将这些信息发送至消息队列
(7)重新从消息队列中获得该数据,重试操作。

监听数据库binlog日志工具分析:canal、Maxwell、Databus、DTS:https://blog.csdn.net/weixin_38071106/article/details/88547660

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值