• 缓存一致性,删除缓存,写入缓存,缓存击穿,缓存穿透,缓存雪崩


    一、DB操作与缓存操作一致性的问题

    当你既要更新数据库,又要更新缓存的时候,就涉及到一致性的问题,如何保证两者能同时成功呢?

    1. 通过消息队列,将对缓存的操作放到队列实现,可以确保其成功。
    2. 订阅 binlog 日志,需要借助 canal 工具来知道数据库做了哪些操作,然后去操作缓存。
    3. 通过 dtm 二阶段消息,也可以确保缓存被操作成功。

    二、如何删除缓存

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

    1. 线程A删除缓存,还没来得及更新数据库。
    2. 线程B进来了,发现缓存没有,读取数据库(此时是旧值),将旧值回填缓存。
    3. 线程A更新了数据库。

    会出现缓存中的数据是旧值。

    缓解方法

    1. 设置简短的过期时间兜底,在这个时间内会出现不一致,缺点是数据库负载会加大。
    2. 延时双删,线程A删除缓存,更新数据库,sleep一会,再删一次缓存,这个睡眠时间是个问题,所以没办法根治。
    3. 在应用层引入类似版本的机制,对应用层有要求,通用性受限,不易复用。

    2、先更新数据库再删缓存

    1. 线程A更新了数据库中的值,但还没来得及删除缓存中的值。
    2. 线程B读取到缓存,此时为旧值。
    3. 线程A删除缓存。

    这种情况总体对业务影响较小。一般在生产环境中,也推荐大家采用该模式。

    三、如何写入缓存

    1. 线程A发现缓存为空,查询数据库,准备回填缓存的时候发生了阻塞。

    2. 线程B发现缓存为空,查询数据库,此时看到的值为新值,因为其他线程修改了数据,回填缓存。

    3. 线程A苏醒过来,回填缓存,此时是旧值。

    会出现缓存中的数据是旧值。

    如果要想解决这种问题,那就只能在读缓存的时候加分布式锁,当然在这个过程中可以做一些优化,具体可以使用 rockscache它的说明,具体原理图

    img

    四、缓存击穿

    前面说到,我们应该先更新数据库,再删除缓存,那么对于热点数据,突然把缓存删了会导致缓存击穿,对数据库造成巨大冲击,针对这种情况,我们需要限制最终去到数据库的流量,我们可以在进程内部加锁,也就是单飞模式,这样每个进程只有一个查询数据库的操作,当然如果你的项目服务器很多,那么对数据库的查询也会很多,那么只能使用分布式锁来加以限制。

    五、缓存穿透

    如果请求的数据在数据库中也不存在,那么为了节省缓存空间一般是不会缓存它的,这就会导致这些请求都会一次次的被打到数据库,这就是缓存穿透。

    首先,如果预防住了缓存击穿,那么在一点程度上也减轻了缓存穿透的危害,除此之外,我们还可以引入布隆过滤器将这些恶意的key存起来。

    六、缓存雪崩

    如果在某一个时刻,缓存大面积同时过期,那么这就是缓存雪崩,预防的方式也很简单,为不同的key设置不同的过期时间,过期时间最好带一个随机数。

  • 相关阅读:
    python编程题3
    Java IO流:Buffered处理流、对象处理流
    数据分析案例-顾客购物数据可视化分析(文末送书)
    钉钉群机器人撤回信息-实操详细教程
    C语言--冒泡排序和简答选择排序
    【毕业设计】前后端分离——解决cookies跨域
    Rust4.1 Managing Growing Projects with Packages, Crates, and Modules
    LeetCode Cookbook 数组习题(5)
    自研爬虫框架的经验总结(理论及方法)
    【小程序从0到1】小程序常用组件一览
  • 原文地址:https://blog.csdn.net/raoxiaoya/article/details/125439881