Redis篇之双写一致性

一、什么的双写一致性

1.定义

双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致。

2.正常情况

Redis篇之双写一致性_第1张图片

读操作:缓存命中,直接返回;缓存没命中查询数据库,写入缓存,设定超时时间。

写操作:延时双删。

3.非正常情况

(1)先删除缓存,再修改数据库

                                          Redis篇之双写一致性_第2张图片

缓存和数据库的初始数据:                                                        对应线程1的第一步操作:

Redis篇之双写一致性_第3张图片                                                                       Redis篇之双写一致性_第4张图片

对应线程2的操作:                                                                      对应线程1的第二步操作:

Redis篇之双写一致性_第5张图片                                                                           Redis篇之双写一致性_第6张图片

最后,可以发现缓存的数据与数据库的数据不一致了,也就是脏数据

(2)先修改数据库,再删除缓存

                                    Redis篇之双写一致性_第7张图片

初始数据如下图,由于缓存数据超时,线程1只能查数据库,拿到的数据为10。

Redis篇之双写一致性_第8张图片               

线程2这时先更新数据库的数据,再删除缓存。                        

 Redis篇之双写一致性_第9张图片

最后,线程1把之前读到的数据也就是10放入缓存之中。

Redis篇之双写一致性_第10张图片

最后,可以发现缓存的数据与数据库的数据不一致了,也就是脏数据

4.延时双删

        从非正常情况就可以知道为什么需要再删除一次缓存,就是为了降低脏数据的出现。那为什么要延时呢?因为我们的数据库一般是主从模式的,就是读写分离的,数据需要从主节点同步到从节点,所以需要延时删除缓存。但是,这个延时的时间却不好控制。综述,延时双删可以降低脏数据出现的风险,但不能保证数据的强一致性。

5.那怎么保证数据强一致性

(1)分布式锁

        缺点:性能低。

Redis篇之双写一致性_第11张图片

(2)读写锁

因为数据库大多数都是读多写少。所以对读操作加共享锁,其他线程都可以读操作,但不能写操作。在写操作加排他锁,其他线程不得读也不能写。这样不仅保证了数据的强一致性,还兼顾了性能。

Redis篇之双写一致性_第12张图片

读写锁的代码可以参考网上的,核心就是使用redission,获取读写锁然后操作。

(3)异步通知

实际开发中,大部分都可以有延时的,主要是使用消息队列(mq)。

Redis篇之双写一致性_第13张图片

(4)使用Canal

        Canal是基于数据库的主从同步来实现的。通过二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询 (SELECT、SHOW)语句。这样的优点就是不会在业务代码上有复杂其他的代码了。

Redis篇之双写一致性_第14张图片

6.面试的时候应该如何回答

(1)强一致性的业务回答

面试官:redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)

候选人:就说我最近做的这个项目,里面有xxxx(根据自己的简历上写)的功能,需要让数据库与redis高度保持一致,因为要求时效性比较高,我们当时采用的读写锁保证的强一致性。

我们采用的是redisson实现的读写锁,在读的时候添加共享锁,可以保证读读不互斥,读写互斥。当我们更新数据的时候,添加排他锁,它是读写,读读都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。这里面需要注意的是读方法和写方法上需要使用同一把锁才行。

面试官:那这个排他锁是如何保证读写、读读互斥的呢?

候选人:其实排他锁底层使用也是setnx,保证了同时只能有一个线程操作锁住的方法

面试官:你听说过延时双删吗?为什么不用它呢?

候选人:延迟双删,如果是写操作,我们先把缓存中的数据删除,然后更新数据库,最后再延时删除缓存中的数据,其中这个延时多久不太好确定,在延时的过程中可能会出现脏数据,并不能保证强一致性,所以没有采用它。

(2)允许有延时的业务回答

面试官:redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)

候选人:嗯!就说我最近做的这个项目,里面有xxxx(根据自己的简历上写)的功能,数据同步可以有一定的延时(符合大部分业务)

我们当时采用的阿里的canal组件实现数据同步:不需要更改业务代码,部署一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后在通过canal的客户端获取到数据,更新缓存即可。

你可能感兴趣的:(redis,数据库,缓存,面试)