Redis

解决缓存和数据库数据不一致问题

2020-12-28  本文已影响0人  扮鬼之梦

只读缓存

操作顺序 是否高并发 潜在问题 现象 应对方案
先删除缓存,再更新数据库 缓存删除成功,数据库更新失败 会从数据库读到旧值 重试数据库更新
先删除缓存,再更新数据库 缓存删除后,尚未更新数据库,有并发读请求 并发读请求读到数据库旧值,并更新到缓存,导致之后的读请求读到旧值 延迟双删
先更新数据库,再删除缓存 数据库更新成功,缓存删除失败 会从缓存读到旧值 重试缓存删除
先更新数据库,再删除缓存 数据库更新成功,尚未删除缓存 会从缓存读到旧值 不一致的情况短暂存在,对业务影响较小

读写缓存

操作顺序 是否高并发 潜在问题 现象 应对方案
先更新缓存,再更新数据库 缓存更新成功,数据库更新失败 会从缓存中读到最新值,短期影响不大 重试数据库更新
先更新数据库,再更新缓存 数据库更新成功,缓存更新失败 会从缓存读到旧值 重试缓存更新
1、先更新数据库,再更新缓存 写+读并发 线程A先更新数据库,之后线程B读取数据,之后线程A更新缓存 B会命中缓存,读取到旧值 A更新缓存前,对业务有短暂影响
2、先更新缓存,再更新数据库 写+读并发 线程A先更新缓存成功,之后线程B读取数据,此时线程B命中缓存,读取到最新值后返回,之后线程A更新数据库成功 B会命中缓存,读取到最新值 业务没影响
3、先更新数据库,再更新缓存 写+写并发 线程A和线程B同时更新同一条数据,更新数据库的顺序是先A后B,但更新缓存时顺序是先B后A,这会导致数据库和缓存的不一致 数据库和缓存的不一致 写操作加分布式锁
4、先更新缓存,再更新数据库 写+写并发 与场景3类似,线程A和线程B同时更新同一条数据,更新缓存的顺序是先A后B,但是更新数据库的顺序是先B后A,这也会导致数据库和缓存的不一致 数据库和缓存的不一致 写操作加分布式锁

场景1和2对业务影响较小,场景3和4会造成数据库和缓存不一致,影响较大。也就是说,在读写缓存模式下,写+读并发对业务的影响较小,而写+写并发时,会造成数据库和缓存的不一致。

针对场景3和4的解决方案是,对于写请求,需要配合分布式锁使用。写请求进来时,针对同一个资源的修改操作,先加分布式锁,这样同一时间只允许一个线程去更新数据库和缓存,没有拿到锁的线程把操作放入到队列中,延时处理。用这种方式保证多个线程操作同一资源的顺序性,以此保证一致性。

综上,使用读写缓存同时操作数据库和缓存时,因为其中一个操作失败导致不一致的问题,同样可以通过消息队列重试来解决。而在并发的场景下,读+写并发对业务没有影响或者影响较小,而写+写并发时需要配合分布式锁的使用,才能保证缓存和数据库的一致性。

另外,读写缓存模式由于会同时更新数据库和缓存,优点是,缓存中一直会有数据,如果更新操作后会立即再次访问,可以直接命中缓存,能够降低读请求对于数据库的压力(没有了只读缓存的删除缓存导致缓存缺失和再加载的过程)。缺点是,如果更新后的数据,之后很少再被访问到,会导致缓存中保留的不是最热的数据,缓存利用率不高(只读缓存中保留的都是热数据),所以读写缓存比较适合用于读写相当的业务场景。

上一篇下一篇

猜你喜欢

热点阅读