• redis缓存一致性以及解决方案


    一致性问题:
    首先要到redis里面读取缓存,如果没有缓存,那么就到mysql里面去取数据,并且将其放置在缓存中

    关于解决缓存一致性的问题,不难想到主要有两种解决方案,双更模式和删除模式


    双更模式:


    双更模式,顾名思义就是更新两次,一次更新redis,一次更新mysql
    不难想到,如果我们先更新redis,再更新mysql的话,是不是就可以保证每次缓存中的数据都是最新的了?
    但是这样做是有问题的,比如如果我们更新mysql的时候失败了怎么办?更新数据库可能会失败,发生了回滚。所以,最后“缓存里的数据”和“数据库的数据”就不一样了,也就是出现了数据一致性问题。

    那如果先更新mysql,再更新redis呢?
    由于数据库和 Redis 的操作,并不是原子的,它们的执行时长也不是可控制的。当两个请求的时序发生了错乱,就会发生缓存不一致的情况。

    综上,双更模式下,数据不一致的概率较大,一般不建议使用双更模式。


    删除模式


    删除模式即更新数据时,删除redis,查询时重新从数据库中加载数据。
    先删除缓存
    请求A删除了某个 key 的值,这时候有另外一个请求B 到来,那么它就会击穿到数据库,读取到旧的值。无论操作A更新数据库的操作持续多长时间,都会产生不一致的情况。
    后删除缓存
    后删除缓存不会出现上述问题。一般情况下这种方式可以解决大部分问题,也是最常用的解决方案。
    但是在高并发的情况下,仍有可能出现不一致的情况。场景如下:
    有一系列的高并发操作,一直执行着更新、删除的动作。某个时刻,它更新数据库的值为 1,然后删除了缓存。
    正在这时,有两个请求发生了:

    一个是读操作,读到的当然是数据库的旧值 1,我们记作操作 A;
    同时,另外一个请求发起了更新操作,把数据库记录更新为 2,我们记作操作 B。
    一般情况下,读取操作都是比写入操作快的,但我们要考虑两种极端情况:

    一种是这个读取操作 A,发生在更新操作 B 的尾部;
    一种是操作 A 的这个 Redis 的操作时长,耗费了非常多的时间。比如,这个节点正好发生了 STW。(条件比较苛刻)
    那么很容易地,读操作 A 的结束时间就超过了操作 B 删除的动作。

    实际上,你也无法控制它们的执行顺序。只要发生这种情况,大概率数据库和Redis的值会不一致。


    解决方案:


    延迟双删
    延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再sleep一段时间,然后再次删除缓存。
    sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。
    流程如下:
    线程1删除缓存,然后去更新数据库
    线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存
    线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除
    如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值
    设置较小的缓存时间
    俗称闪电缓存,即把缓存的失效时间设置非常短,比如 5秒。一旦失效,就会再次去数据库读取最新数据到缓存,即数据不一致只会在短时间内不一致。但这种方式,在非常高的并发下,同一时间对某个 key 的请求击穿到 DB,产生缓存击穿问题
    消息队列
    先更新数据库,成功后往消息队列发消息,消费到消息后再删除缓存,借助消息队列的重试机制来实现,达到最终一致性的效果。
    在这里插入图片描述

    进阶版消息队列
    一般大公司本身都会有监听binlog消息的消息队列存在,主要是为了做一些核对的工作。
    这样,我们可以借助监听binlog的消息队列来做删除缓存的操作。这样做的好处是,不用你自己引入,侵入到你的业务代码中,中间件帮你做了解耦,同时,中间件的这个东西本身就保证了高可用。
    当然,这样消息延迟的问题依然存在,但是相比单纯引入消息队列的做法更好一点。
    在这里插入图片描述


    支持事务的缓存


    Apache geode是不错的Redis的替换,支持事务,缓存不一致好多时候是Redis不支持事务引起,Geode的商业版本GemFire就是当年支持12306的神器,稳定性,性能都很好
    在这里插入图片描述
    链接如下
    https://github.com/apache/geode

  • 相关阅读:
    【大厂算法笔试题 | 13】归并排序引出的系列问题(小和、逆序对、特定逆序对)
    Idea代码上传至Git完整教程(阿里云)
    【一起来学C++】————(11)STL之vector容器容器
    儿童玩具外贸出口认证知识干货
    深度学习数据集的文本制作和读取
    软阴影(PCF、PCSS)
    Map集合的entrySet()方法
    使用java mail SMTPTransport发送邮箱,本地秒到,一上服务器就20-30s左右,生产环境直接发送失败。
    微信小程序预约视频号直播
    重绘(Repaint)和回流(Reflow)(重排),以及如何优化?
  • 原文地址:https://blog.csdn.net/xiaocaij_icai/article/details/128052145