欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > Day05:缓存双写一致性

Day05:缓存双写一致性

2024/12/26 23:24:26 来源:https://blog.csdn.net/m0_45253972/article/details/144173000  浏览:    关键词:Day05:缓存双写一致性

redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性–强一致)
一种是一致性要求比较高同步方案,另一种是允许延迟一致异步通知

什么是双写一致性?

双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致
在这里插入图片描述
读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设置超时时间。

写操作:延迟双删

什么是延迟双删?

延迟双删是先删除缓存,数据库修改完成之后,再延迟删除一次缓存,就是为了降低脏数据的出现。一般情况下数据库是主从模式,它是读写分离的。延时删除的目的就是为了让主数据库将数据同步到从数据库,这个延时也会出现问题因为多长时间不好控制,在延时的过程中也可能出现脏数据,做不到绝对的强一致。
在这里插入图片描述
先删除缓存,再修改数据库:
初始时缓存和数据库中的数据都是10,线程1执行删除缓存操作。线程2查询缓存未命中,查询数据库为10 ,然后写入到缓存中,此时缓存的数据为10。线程1再执行修改数据库操作,那么数据库中的数据就为20。此时出现了数据的不一致性也就是脏数据的情况。
在这里插入图片描述
先修改数据库再删除缓存:
初始数据库和缓存中的数据都是10,如果缓存过期了,也就是缓存中没有数据。线程1查询缓存未命中,就会查询数据库中的数据10。在线程1还没有同步到缓存之前,线程切换到线程2。线程2直接去更新数据库中的数据为20,然后再去删除缓存。线程1再将原来的10写入到缓存中。
在这里插入图片描述
先删除缓存还是先修改数据库都会出现问题。

解决缓存双写一致性方法:

方法一:加读写锁

使用读写锁的方式虽然何以保持数据的强一致性,但是性能相对低。读写锁方式比较适合业务必须强一致的情况下。
在写数据和读数据的时候添加分布式锁(互斥锁),只能有一个线程读或写,操作完成之后解锁成功才能让其他线程读写,这就能绝对保证数据的一致性,但是性能很低。由于存入缓存的数据都是读多写少,可以利用读写锁控制。当读数据的时候添加共享锁,允许其他线程读,但是不允许其他线程写。当写数据的时候添加排他锁,阻塞其他线程的读和写的操作
在这里插入图片描述
读写锁在redisson中已经提供了,首先通过getReadWriteLock获取读写锁,然后调用其readLock或者writeLock方法拿到读锁或者写锁。
在这里插入图片描述

方法二:异步通知

异步通知保证数据的最终一致性,允许短暂的不一致,在开发中该方法是主流的。
方式一:使用MQ中间件:
当修改数据写入数据到MySQL数据库后,就会发布消息给MQ,在缓存服务cache-service中监听MQ,最终再去更新缓存。消息发出后什么时候接收到消息,什么时候同步缓存肯定是有延迟的,需要保证MQ的可靠性。
在这里插入图片描述
方式二:使用Canal中间件
Canal是阿里的一个中间件,它主要是基于mysql的主从来实现同步。当有数据修改写入到数据库后,数据库一旦发生变化就会将这个变化记录到BINLOG二进制文件中。canal通过binlog日志文件与数据的变化,当需要的表数据发生变化后,就可以在缓存服务获取变化之后的数据,然后更新到缓存。
在这里插入图片描述

利用canal中间件,不需要修改业务代码,它是伪装了mysql的一个从节点,读取binlog数据更新缓存。如果业务能接收短暂的延迟,canal这种实现方式就可以。正常情况下是感受不到延迟的,除非在大量并发下才能感受到到延迟。

总结:

redis做为缓存,mysql的数据如何与redis进行同步?
方法一:异步方案
例如:把文章的热点数据存入到缓存中,虽然是热点数据,但是实时性要求并没那么高,所以采用异步的方案。
允许延时一致的业务,采用异步通知。
使用MQ的中间件完成数据的同步,当mysql的数据更新之后,会法发送一条消息通知给MQ。缓存服务cache-service需要接收这个消息,把数据同步到缓存中。这需要保证MQ的可靠性。
采用阿里的canal组件实现数据同步,不需要修改业务代码,部署一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后通过canal的客户端获取到数据,更新缓存即可。
方法二:读写锁
例如:把抢劵的库存存入到缓存中,这个需要实时的进行数据同步,为了保证数据的强一致性,需要采用redisson提供的读写锁来保证数据的同步。
在读的时候添加共享锁,可以保证读读不互斥,读写互斥。更新数据的时候,添加排他锁,它是读写,读读都互斥,这样保证写数据的同时不会让其他线程读脏数据。这里面需要注意的是读方法和写方法上需要使用同一把锁才行。
排他锁是如何保证读写、读读互斥的?
排他锁底层使用的也是setnx,保证了同时只能有一个线程操作锁住的方法。
什么是延时双删?为什么不使用延时双删?
延时双删,如果是写操作,我们先把缓存中的数据删除,然后更新数据库,最后再延时删除缓存中的数据,其中这个延时多久不太好确定,在延时的过程中可能会出现脏数据,并不能保证数据的强一致性,所以不采用它。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com