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,保证了同时只能有一个线程操作锁住的方法。
什么是延时双删?为什么不使用延时双删?

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

相关推荐
小七-七牛开发者3 天前
TokenPilot:让 LLM Agent 长会话成本降 60%+ 的上下文管理
缓存·agent·token·context·上下文·推理成本
ofoxcoding10 天前
在AI API聚合平台配置DeepSeek V3.2提示词缓存实战:快速接入与成本优化指南
人工智能·spring·缓存·ai
NeilYuen10 天前
gRPC结合FAISS构建AI助手语义缓存模块(一):设计
人工智能·缓存·faiss
taocarts_bidfans10 天前
反向海淘跨境缓存架构优化:taocarts Redis分层缓存实战技术
redis·缓存·架构·反向海淘·taocarts
退休倒计时10 天前
【每日一题】LeetCode 146. LRU 缓存 TypeScript
算法·leetcode·缓存·typescript
炘爚10 天前
Linux——Redis
数据库·redis·缓存
小挪号底迪滴10 天前
Redis 和 MySQL 数据不一致怎么办?缓存更新策略实战
redis·mysql·缓存
闪电悠米10 天前
黑马点评-Redis ZSet-实现关注 Feed 流
服务器·网络·数据库·redis·缓存·junit·lua
Saniffer_SH11 天前
【高清视频】Gen6 服务器还没到,Gen6 SSD 怎么测?Emily 现场演示三种测试环境
人工智能·驱动开发·测试工具·缓存·fpga开发·计算机外设·压力测试