Redis:如何保证Redis缓存和数据库的数据一致性?

        在我们的项目中,通常使用redis去做缓存,然而,有些时候会出现缓存和数据库数据不一致从而导致用户读取到的数据是错误的问题。

何时会产生数据不一致的问题呢?

下图是用户查询缓存的一般顺序

当我们的用户发起一次修改数据时,数据库进行数据修改,然而,在修改数据库时,系统发生了延迟,导致数据还未修改成功时,另一个用户去缓存中读数据,等到读取到数据后,数据库才修改完毕,但此时缓存中的数据是旧数据,这就导致了缓存与数据库的数据不一致的问题。

如何解决呢?

        让我们循序渐进的来寻找解决思路

我们为什么不直接修改缓存,而是取删除缓存呢?

  1. 简化逻辑:删除缓存可以避免复杂的逻辑判断和处理。如果直接修改缓存,可能需要考虑多种情况,比如缓存的数据结构是否需要改变、缓存的过期时间如何处理等。而删除缓存则可以简化这些逻辑,只需要删除缓存,然后在需要的时候重新从数据源获取最新数据并重新缓存。

  2. 确保数据一致性:如果直接修改缓存,可能会出现一种情况,即修改了缓存但是未能成功更新数据库。这样就会导致缓存中的数据和数据库中的数据不一致。而删除缓存后重新获取最新数据,可以确保从数据库获取的数据和缓存中的数据保持一致。

  3. 避免并发冲突:在高并发的场景下,如果多个请求同时修改缓存,可能会导致并发冲突和数据不一致的问题。而删除缓存后重新获取最新数据,可以避免这种并发冲突,保证数据的一致性。

先操作数据库还是先操作缓存?

1、先删除缓存再修改数据库

        还是会引起数据不一致的问题,A用户去修改,修改前删除缓存,但修改数据库时遇到了延迟,B用户去查,发现缓存没数据,则去查数据库,数据库查到之后,返回给缓存,A用户还没完成修改,缓存中放入的还是脏数据,引起数据不一致

2、先删除缓存再修改数据库,延迟一段时间,再删除缓存

        可以解决数据不一致问题,但先删除缓存显得没必要了。

3、先修改数据库,延迟一段时间,再删除缓存

        可以解决数据不一致问题

为什么要延迟一段时间呢?

        为了防止A线程修改完数据库时将缓存删除了,但是此时B线程已经读取到的是数据库修改前的数据,若不延迟,B线程放入缓存中的数据则可能是旧数据,所以要延迟删除。

        以上的2、3都可以解决数据不一致的问题,但是还是有可能造成B用户的一次读取到脏数据的可能,也就是我们这样做无法保证强一致性,只能保证最终一致性。强一致性需要加锁了,使修改操作变为原子操作,但是这样做效率很低,我们使用redis目的就是为了提高性能,所以我们没必要保证他的强一致性。

        但是会出现一个新的问题,若修改数据库之后,删除缓存失败了怎么办?

        解决方法很简单,就是当删除缓存操作失败时,发送一个异步消息到MQ中,系统对MQ进行监听,若监听到删除失败,则进行重试删除。

        但是这样做,有一个缺点,那就是MQ的操作和程序的耦合度太高了

        为了解决这个问题,可以使用canal,canal是阿里的一款开源框架,基于mysql日志解析,提供增量数据订阅和消费

        Canal提供了各种语言的客户端,当Canal监听到binlog变化时,会通知Canal的客户端,从而进行一些增值的操作。        

        A线程向数据库发出修改请求,修改延迟,B线程读缓存,缓存没有,去读数据库,将旧数据保存到缓存 ,A线程修改完毕,此时canal监听到数据库发生改变,将变更的数据发送给一个客户端(在这里是springboot程序),客户端去执行删除缓存的操作,若删除失败,则发送异步请求到MQ,指明删除失败的key,MQ被监听到时,重试删除,这样就实现了解耦。

总结:

        以上就是Redis与数据库一致性问题的完整解决方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值