zoukankan      html  css  js  c++  java
  • 缓存雪崩、穿透、热点key

    缓存雪崩

    • 概念

    因为缓存失效,导致请求直接命中数据库。导致 DB 负荷大增,最终宕机。

    • 如何解决

    1)缓存高可用

    通过搭建缓存的高可用,避免缓存挂掉导致无法提供服务的情况,从而降低出现缓存雪崩的情况。

    假设我们使用 Redis 作为缓存,则可以使用 Redis Sentinel 或 Redis Cluster 实现高可用。

    2)本地缓存

    如果使用本地缓存(Ehcache、Guava Cache )时,即使分布式缓存挂了,也可以将 DB 查询到的结果缓存到本地,避免后续请求全部到达 DB 中。

    3)请求 DB 限流(Guava RateLimiter、Sentinel)

    通过限制 DB 的每秒请求数,避免 DB 宕机。这样至少能有两个好处:

    可能有一部分用户,还可以使用,系统还没死透。
    未来缓存服务恢复后,系统立即就已经恢复,无需在处理 DB 也挂掉的情况。

    4)服务降级(Hystrix、Sentinel)

    如果请求被限流,或者请求 DB 超时,我们可以服务降级,提供一些默认的值,或者友情提示。

    缓存穿透

    缓存穿透,是指查询一个不存在的数据,当缓存不命中时,会从 DB 查询到数据,再更新到缓存中,并且处于容错考虑,如果从 DB 查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 去查询。

    在流量大时,可能 DB 就挂掉了,要是有人利用不存在的 key 频繁攻击我们的应用,这就是漏洞。比如使用程序瞬间产生大量的请求,攻击服务器。

    • 如何解决
    1. 方案一,缓存空对象:当从 DB 查询数据为空,我们仍然将这个空结果进行缓存,具体的值需要使用特殊的标识,能和真正缓存的数据区分开。另外,需要设置较短的过期时间,一般建议不要超过 5 分钟。但是当客户端同一时刻发起大量请求时,会导致redis垃圾缓存过多,可能导致redis宕机。个人认为客户端同一时刻发起大量请求时,应该使用限流机制,避免大量垃圾请求进入后台。如果很多客户端发起DDOS攻击,就不太好防了。

    2. 方案二,使用互斥锁排队(或者分段锁),即根据key获取value值为空时,锁上,从数据库中load数据后再释放锁。若其它线程获取锁失败,则等待一段时间后重试。这里要注意,分布式环境中要使用分布式锁,单机的话用普通的锁(synchronized、Lock)就够了。

    3. 方案三,此方案摘自网络,BloomFilter 布隆过滤器:在缓存服务的基础上,构建 BloomFilter 数据结构,在 BloomFilter 中存储对应的 KEY 是否存在,如果存在,说明该 KEY 对应的值为空。那么整个逻辑的如下:

      1、根据 KEY 查询缓存。如果存在对应的值,直接返回;如果不存在,继续向下执行。

      2、根据 KEY 查询在缓存 BloomFilter 的值。如果存在值,说明该 KEY 不存在对应的值,直接返回空;如果不存在值,继续向下执行。

      3、查询 DB 对应的值,如果存在,则更新到缓存,并返回该值。如果不存在值,更新到缓存 BloomFilter 中,并返回空。

    热点key

    在实际请求中,可能存在热点key的情况,导致缓存宕机。比如某个流量明星微博发了某条信息,几千万人都在看,这条微博就会成为热点key。

    • 如何解决

    识别热点key,如发现是热点key,缓存到本地。同时做好熔断、降级处理。盗用网络的一张图片(不记得出处了),如下:

  • 相关阅读:
    Maven 集成Tomcat插件
    dubbo 序列化 问题 属性值 丢失 ArrayList 解决
    docker 中安装 FastDFS 总结
    docker 从容器中拷文件到宿主机器中
    db2 相关命令
    Webphere WAS 启动
    CKEDITOR 4.6.X 版本 插件 弹出对话框 Dialog中 表格 Table 自定义样式Style 问题
    SpringMVC JSONP JSON支持
    CKEDITOR 3.4.2中 按钮事件中 动态改变图标和title 获取按钮
    git回退到远程某个版本
  • 原文地址:https://www.cnblogs.com/iiot/p/11010592.html
Copyright © 2011-2022 走看看