缓存与数据库双写一致性问题及最佳解决方案

原文链接:https://www.jianshu.com/p/dc1e5091a0d8

在大型互联网应用当中如果你的应用引入了缓存机制,那么有一个大前提就是你的业务场景上必须得接受数据的新鲜度上有可能会有一定时间的延迟。删除缓存失败是一个极小概率事件,且在不能保证所有操作100%成功的几率下,采用JOB补偿的机制是目前比较成熟的解决方案。大并发量写请求的应用,不可能去实时写DB,基本都采用队列+消息异步写DB的机制,不然会有大量的并发问题。

缓存机制介绍

如今利用缓存机制来提高查询效率已被广泛用在各大生产环境,查询数据的一般流程如下所示

在没有更新数据的情况下,数据库和缓存的数据是保持一致的,当时当要执行数据库的更新操作时,数据库和缓存就会出现不一致的情况。

首先需要明确的是,既然系统引入缓存机制,就必须接受系统会出现数据不一致的情况发生,我们不可能完全避免,只能尽量减少不一致的时间,达到最终一致性。常见的有以下几种方案:

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

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

  • 缓存延时双删,即先删除一次缓存,再更新数据库,延时一小段时间后再次删除缓存

  • 监听MySQL binlog进行缓存更新

之所以缓存不采取更新操作而是直接删除,是因为高并发环境下,无论是先操作数据库还是后操作数据库,如果加上缓存更新,那就更容易导致数据库与缓存的不一致(删除缓存直接且简单得多)

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

1、线程A删除了缓存

2、线程B读不到缓存,然后去DB中读取了旧数据

3、线程B将旧数据写入缓存

4、线程A更新DB

这样一来,DB中是新的数据,缓存中是旧的数据,造成了不一致问题。

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

1、缓存已失效时,线程A从DB中读取到旧值

2、线程B更新数据库,并删除了缓存

3、线程A将旧值写入缓存

这样一来,DB中是新的数据,缓存中是旧的数据,造成了不一致问题。

延时双删

为解决先删除缓存,再更新数据库可能出现的问题,出现了该方案

1、线程A删除了缓存

2、线程B读不到缓存,然后去DB中读取了旧数据

3、线程B将旧数据写入缓存

4、线程A更新DB

5、延时异步再删除缓存

上面已经分析了,如果没有第5步,会出现DB是新值,缓存是旧值的情况。加上第五步之后,4-5之间的这段时间,还是会出现数据不一致,但是一旦执行了第5步,数据又将达成最终一致性。

评论