Redis缓存一致性的问题

        我在项目中使用redis的一个场景就是做缓存,将某某功能中的id查询结果通过spring-data-redis的repository缓存到redis中。
        对于缓存的操作我们大体上用的是facebook的cap方案。就是在查询操作中先查redis,如果没有,就去查mysql,查完之后会。把mysql查询出来的数据存到redis中。对于修改和删除操作,先操作mysql执行修改和删除sql语句,然后去redis中删除这些变动的数据。cap可以解决所有的双写并发问题,和绝大多数的。读写并发问题,但是有一种读写并发问题它解决不了。
        就是我们A先去读redis此时redis没有数据就去mysql读,并且读到的是旧的数据。但是此时B去修改了mysql旧数据变成新的数据并且B要去删除Redis。然后A又把旧的数据写到redis中 这时redis中的数据就是脏数据。
        对于这种问题我们当时也分析了facebook为什么没有去处理这种情况,我们觉得因为大多数系统对数据的操作都是读多写少,在这种情况下,这种读写并发出问题是小概率事件。而且也并不是说只要出现读写并发就一定会出现问题,例如B改mysql 然后A读redis没有再去读mysql A再去写旧数据,最后B把旧数据删除。
        另外,就算读写并发出现问题,脏数据也不会一直存在,我们在写操作存缓存的操作中,会给他一个过期自动删除的时间。所以即便出现读写不一致的情况,实际上也会过期自动删除。但是后面由于客户的要求,项目经理对cap方案做出了修改,采用了比较流行的延迟双删方案。延迟双删方案最大的改进点在于把修改删除sql语句之后的删除操作进行了延迟。我们在这里采用的是jdk的线程池执行延迟任务的方式实现延迟删除。
        因为延迟删除将写操作中的删除缓存推迟到了读操作写缓存之后  所以不管怎么样旧数据一定是会被删除的。但是这个延迟删除时间设置多久才能保证写操作的删除redis在读mysql的存redis之后。理论上来说是越长越保险,我们是这么分析这个问题的。cap方案最大数据不一致再删除窗口期是30秒。
        最小时长为0秒。在延迟删除的方法中,我们故意延迟五秒删除,这样的话就会百分之百有5秒的窗口期,为了避免这个百分之百的窗口期,目前主流的方案都是要求删除两次。
对于这个删两次的操作,我以前也是纠结了半天,为什么这个多出来的删除在更新mysql之前,而不是之后。
        后面我才发现,如果是改数据库再删redis再延迟删除redis这样第一次如果失败需要回滚mysql操作
如果是先删除redis再改mysql再延迟删除这样的话失败就直接返回 不用再执行mysql操作了,有一种快速失败的效果。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值