[redis] redis和mysql之间的数据一致性

作者:孤独烟 出处: http://rjzheng.cnblogs.com/

1、先更新数据库,再更新缓存

不推荐,面试答这个稳挂

2、先删缓存,再更新数据库,下次查询再更新缓存

会出现如下问题:

  1. 请求A想要更新数据库,先删除了缓存
  2. 请求B过来了,查询缓存没有,于是查询数据库并更新了缓存
  3. 请求A更新了数据库
  4. 此时缓存里面存储的还是之前的旧值

这个情况发生的概率还是很大的,因为写操作肯定是比读操作耗时的,所以完全有可能在写的过程中完成了读操作

解决办法:延时双删:在删除缓存并更新数据库之后,等待一定时间后再次删除缓存

那么具体设置多久呢:一般是在读请求耗费时间的基础上加上几百ms,如果数据库配置了主从同步的话,还得再加上同步的时间

这个方案也不是很好,也不建议面试的时候回答,因为延时在高并发情况下是不可接受的

3、先更新数据库,再删缓存,下次查询再更新缓存

当然他也存在问题:

  1. 假设现在缓存中没有,请求A想要查询于是查询数据库
  2. 请求B更新了数据库并删除了缓存(因为缓存没有,所以删除啥也没做,只是表达删除这一步走完了)
  3. 请求A去更新缓存,此时缓存中为旧值

那么这种情况发生的概率大吗,当然不大,因为上述情况想要发生,就要求请求B的写请求执行完了,请求A的读请求还没有执行完。我们都知道,写请求是远慢于读请求的,所以这种情况发生的概率很小

那么更重要的问题来了,删除缓存失败了怎么办

方案一:将需要删除的key发送至消息队列,然后取出来消费,直到删除成功。但是这样会对业务代码造成大量的侵入

方案二:启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。

  • 更新数据库数据;
  • 数据库会将操作信息写入binlog日志当中;
  • 订阅程序提取出所需要的数据以及key;
  • 另起一段非业务代码,获得该信息;
  • 尝试删除缓存操作,发现删除失败;
  • 将这些信息发送至消息队列;
  • 重新从消息队列中获得该数据,重试操作;

备注说明:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。另外,重试机制,这里采用的是消息队列的方式。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值