一个经典面试题:如何保证缓存与数据库的双写一致性?

2019-05-20  本文已影响0人  田真的架构人生

转自:https://mp.weixin.qq.com/s/9fbXiQe1sc2xpMKfBXNF3w

只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?

Cache Aside Pattern
最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。

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

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

为什么是删除缓存,而不是更新缓存?
主要有以下两点:

比较复杂的数据不一致问题分析
在并发量比较大的情况下,极有可能会出现如下场景:

解决方案:操作串行化

理论上,不管是先更新数据库再删除缓存,还是先删除缓存再更新数据库,只要保证读写操作是串行的,就没有数据一致性的问题。但是在实际操作过程中,如果选择先更新数据库再删除缓存的话,读请求无法得知哪些数据的读取需要串行化(除非去遍历更新数据库的请求队列,代价太高)。所以选择先删除缓存再更新数据库

具体过程:更新数据库之前,先删除缓存,然后根据数据唯一标识,将更新操作路由到一个JVM 内部队列中。读请求过来的时候,发现缓存中无数据(需要串行化),那么将重新进行读取数据+更新缓存的操作,根据数据唯一标识路由到和更新数据库操作的同一个JVM内部队列中。

可选优化点:同一个数据,在队列中可能会存在多个读请求排队,可以做一下过滤,如果发现队列中已经有读请求在排队,那么就不用再放第二个读请求进去了,第二个读请求直接等待前面的操作完成即可(不过这个操作需要遍历队列,另外,第二个读请求还需要做手动同步等待,操作复杂性以及性能不一定会有提高,可选吧)。

一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去。

串行化可以保证一定不会出现不一致的情况,但是它也会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上请求。

上一篇下一篇

猜你喜欢

热点阅读