Redis和DB的一致性问题

Redis和DB的一致性

一,方案
  1. 先更新数据库,更新缓存。不考虑
/*
* 不考虑原因一(线程安全角度)
*/1)线程A更新了数据库
(2)线程B更新了数据库
(3)线程B更新了缓存
(4)线程A更新了缓存
结论:导致线程B更新缓存的数据丢失,产生脏数据
/*
* 不考虑原因二(业务角度)
*/
(1)写多读少的场景:DB通常是写磁盘,Redis通常是写内存,磁盘速度比内存的写慢,在DB压根没写完,就频繁写内存导致性能浪费
(2)如果写DB的值并不是直接写入Redis的,还需要经过复杂计算,无疑是浪费性能,显然删缓存更为合适
  1. 先删除缓存,再更新数据库。常用
/*
*执行步骤
*/1)请求A进行写操作,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询得到旧值
(4)请求B将旧值写入缓存
(5)请求A将新值写入数据库 上述情况就会导致不一致的情形出现。而且,如果不采用给缓存设置过期时间策略,该数据永远都是脏数据。
/*
*最终方案,采用延时双删策略,以下伪代码
*/
public void write(String key,Object data){
        redis.delKey(key);
        db.updateData(data);
        Thread.sleep(1000);
        redis.delKey(key);
    }

/*
* 其中的休眠1秒是平衡读与写操作的时间差异,那么1秒是是如何确定的?
* 休眠多少秒 = 读操作 + 几百毫秒
* 1秒的读操作之后,再删除缓存,是为了删除1秒读操作之内产生的脏数据
*/
/*
*读写分离的架构怎么办?
*/1)请求A进行写操作,删除缓存
(2)请求A将数据写入数据库了,
(3)请求B查询缓存发现,缓存没有值
(4)请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
(5)请求B将旧值写入缓存
(6)数据库完成主从同步,从库变为新值 上述情形,就是数据不一致的原因。
解决方案还是使用延时双删策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms。

/*
*读写分离的架构下,因休眠一定时间后导致的吞吐量降低怎么办?
*/
解决方案:删除缓存改成异步删除,将删除缓存操作另起一个线程,异步写入

/*
*读写分离的架构下,异步删除失败怎么办?
*/
解决方案:将删除缓存操作放入MQ队列,利用MQ队列的重试机制/此处最好是自己用代码控制MQ的ack机制和重试机制
结论:读写分离架构下,基本还是使用延时双删策略,不过延时删除缓存会导致吞吐量降低,所以延时删除改为,MQ的异步删除缓存,利用MQ的ack机制和重试机制确保代码的健壮性,最好用本地消息表去控制ack机制,重试机制和去重机制,若使用MQ出现消息积压的情况,说明生产消息速度 > 消费消息速度,可通过增加消费者数量 去解决,注意MQ需设置备份策略,以保证MQ宕机的情况减少消息的丢失

  1. 先更新数据库,再删除缓存,也称旁路缓存
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值