缓存数据一致性问题

1、问题描述

在实际开发中,我都需要使用redis做缓存来减轻数据的压力,提高查询效率。

如果数据的数据进行了修改,这时候就会出现数据的数据和缓存数据不一致问题。

2、解决方案

2.1、Redis数据删除还是更新

这里我们先要补充一点,当存储的数据发生变化,Redis的数据也要更新的时候,我们有两种方案,一种就是

直接更新Redis数据,调用set;还有一种是直接删除Redis数据,让应用在下次查询的时候重新写入。

这两种方案怎么选择呢?这里我们主要考虑更新缓存的代价。

更新缓存之前,是不是要经过其他表的查询、接口调用、计算才能得到最新的数据,而不是直接从数据库拿到

的值。如果是的话,建议直接删除缓存,这种方案更加简单,而且避免了数据库的数据和缓存不一致的情况。

在一般情况下,我们也推荐使用删除的方案。

所以,更新操作和删除操作,只要数据变化,都用删除。

2.2、先更新数据库还是删除缓存?

2.2.1、先更新数据数据,在删除缓存

正常情况:

更新数据库,成功。

删除缓存,成功。

异常情况:

1、更新数据库失败,程序捕获异常,不会走到下一步,所以数据不会出现不一致。

2、更新数据库成功,删除缓存失败。数据库是新数据,缓存是旧数据,发生了不一致的情况。

这种问题怎么解决呢?我们可以提供一个重试的机制。比如:如果删除缓存失败,我们捕获这个异常,把需要删除的 key,发送到消息队列。让后自己创建一个消费者消费,尝试再次删除这个key。这种方式有个缺点,会对业务代码造成入侵。所以我们又有了第二种方案(异步更新缓存)︰因为更新数据库时会往 binlog写入日志,所以我们可以通过一个服务来监听binlog的变化(比如阿里的canal) ,然后在客户端完成删除key的操作。如果删除失败的话,再发送到消息队列。

2.2.3、先删除缓存,在更新数据库

正常情况:

删除缓存,成功。

更新缓存,成功。

异常情况:

1、删除缓存,程序捕获异常,不会走到下一步,所以数据不会出现不一致。

2、删除缓存成功,更新数据库失败。因为以数据库的数据为准,所以不存在数据不一致的情况。

看起来好像没问题,但是如果有程序并发操作的情况下:

1)线程A需要更新数据,首先删除了Redis缓存。

2)线程B查询数据,发现缓存不存在,到数据库查询旧值,写入redis返回。

3)线程A更新了数据库。

如下图所示:

在这里插入图片描述

这个时候,数据库是新值,redis是旧值,出现了数据不一致的问题。这是由于线程并发造成的。

解决方案:

使用延时双删的策略,在写入数据之后,再删除一次缓存。

A线程:

  1. 删除缓存。
  2. 更新数据库。
  3. 休眠500ms(这个时间,依据读取数据的耗时而定)。
  4. 再次删除缓存。

伪代码

public void write(String key,Object data){
     redis.delKey(key);
	db.updateData(data);
     Thread.sleep(500);
     redis.delKey(key);
}

3.总结

保证缓存一致性的做法是:

  • 数据更新时先删除缓存,在更新数据库。
  • 使用延迟双删,解决多线程并发造成的ABA问题。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值