一般来说,只要我们用到了缓存,就很可能会涉及到缓存与数据库双存储双写,那么只要我们是双写(写数据库,写Redis缓存)操作,就一定会有数据一致性的问题,那么我们该如何解决一致性问题?
一、对于单数据库来说,我们可以这样操作:1、根据你要更新的key,先删除Redis缓存中的数据,2、然后再去更新Mysql数据库中的数据,3、Mysql数据库更新成功之后,再删除Redis中的数据。(简称:双删策略)
注意:第3步的目的是防止在更新Mysql数据库的时候;其他线程正好进来读操作,先访问Redis缓存的数据不存在,然后再去访问Mysql数据库的数据,然后又写到缓存中。这样会造成Redis缓存中的数据和Mysql数据库中的数据不一致。
二、对于数据库主从分离来说,上面的方案可能也会造成缓存和数据库数据不一致的问题;主从数据库,一般都是主数据库写操作,从数据库读操作。由于主从数据库可能存在数据延迟问题,所以当我们执行到上图第4步之后,如果从数据库的数据还没有从主数据库中获取最新的数据,这时候如果有线程进来读操作,会读取从数据库的数据,然后缓存到Redis,此时从数据库的数据是旧数据,所以Redis缓存的数据也是旧数据,就造成的缓存和数据库数据不一致的问题了。
解决方案:
对于主从数据库的双写一致性步骤如上图所示:在第6步的时候,在mq消费端删除redis数据的时候要延时2秒再删除的目的是为了确保mysql主从数据库同步数据成功,不然的话,当另一个线程进来查询的时候,从数据库还是旧的数据。
疑问:在第6步的时候,如果mq队列消费端删除redis数据失败怎么办?
这时候如果redis数据删除失败的时候,可以设置重试删除机制,或者把要删除的数据设置过期时间。
总结:其实不管用什么办法,缓存和数据库的双写一致性肯定是会延迟的,但是最终一定是一致的。这就用到BASE理论的最终一致性的思想。
BASE理论:
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写,BASE是对CAP中一致性和可用性权衡的结果。
最终一致性:
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性