暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据库缓存双写问题

Java开发必备手册 2021-05-24
1817
点击上方蓝字,记得关注我们!
Redis与MySQL双写一致性如何保证?


三个经典的缓存模式

缓存可以提升性能、缓解数据库压力,但是使用缓存也会导致数据不一致性的问题。一般我们是如何使用缓存呢?有三种经典的缓存模式:

Cache-Aside Pattern

Read-Through/Write through

Write behind

Cache-Aside Pattern



Cache-Aside Pattern,即旁路缓存模式


Cache-Aside读流程



Cache-Aside Pattern的读请求流程如下:




读的时候,先读缓存,缓存命中的话,直接返回数据

缓存没有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。


Cache-Aside 写流程



Cache-Aside Pattern的写请求流程如下:




更新的时候,先更新数据库,然后再删除缓存。

Read-Through/Write-Through(读写穿透)

Read/Write Through模式中,服务端把缓存作为主要数据存储。应用程序跟数据库缓存交互,都是通过抽象缓存层完成的。


Read-Through



Read-Through的简要流程如下




从缓存读取数据,读到直接返回

如果读取不到的话,从数据库加载,写入缓存后,再返回响应。

这个简要流程是不是跟Cache-Aside很像呢?其实Read-Through就是多了一层Cache-Provider,流程如下:



Read-Through实际只是在Cache-Aside之上进行了一层封装,它会让程序代码变得更简洁,同时也减少数据源上的负载。


Write-Through




Write-Through模式下,当发生写请求时,也是由缓存抽象层完成数据源和缓存数据的更新,流程如下:

Write behind (异步缓存写入)

Write behind跟Read-Through/Write-Through有相似的地方,都是由Cache Provider来负责缓存和数据库的读写。它两又有个很大的不同:Read/Write Through是同步更新缓存和数据的,Write Behind则是只更新缓存,不直接更新数据库,通过批量异步的方式来更新数据库。


这种方式下,缓存和数据库的一致性不强,对一致性要求高的系统要谨慎使用。但是它适合频繁写的场景,MySQL的InnoDB Buffer Pool机制就使用到这种模式。

操作缓存的时候,删除缓存呢,还是更新缓存?

一般业务场景,我们使用的就是Cache-Aside模式。有些小伙伴可能会问, Cache-Aside在写入请求的时候,为什么是删除缓存而不是更新缓存呢?



我们在操作缓存的时候,到底应该删除缓存还是更新缓存呢?我们先来看个例子:

双写的情况下,先操作数据库还是先操作缓存?




Cache-Aside缓存模式中,有些小伙伴还是有疑问,在写入请求的时候,为什么是先操作数据库呢?为什么不先操作缓存呢?

假设有A、B两个请求,请求A做更新操作,请求B做查询读取操作。


缓存延时双删



先删除缓存

再更新数据库

休眠一会(比如1秒),再次删除缓存。

这个休眠一会,一般多久呢?都是1秒?

这个休眠时间 =  读业务逻辑数据的耗时 + 几百毫秒。为了确保读请求结束,写请求可以删除读请求可能带来的缓存脏数据。


删除缓存重试机制



不管是延时双删还是Cache-Aside的先操作数据库再删除缓存,如果第二步的删除缓存失败呢,删除失败会导致脏数据哦~

删除失败就多删除几次呀,保证删除缓存成功呀~ 所以可以引入删除缓存重试机制





写请求更新数据库

缓存因为某些原因,删除失败

把删除失败的key放到消息队列

消费消息队列的消息,获取要删除的key

重试删除缓存操作

    读取biglog异步删除缓存



重试删除缓存机制还可以,就是会造成好多业务代码入侵。其实,还可以通过数据库的binlog来异步淘汰key。

以mysql为例 可以使用阿里的canal将binlog日志采集发送到MQ队列里面,然后通过ACK机制确认处理这条更新消息,删除缓存,保证数据缓存一致性



END


扫码关注我们
识别二维码,即可关注

目前100000+人已关注加入我们

更多精彩,点击下方“阅读原文”查看。


文章转载自Java开发必备手册,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论