Redis-雪崩,穿透,击穿,无底洞

雪崩

何为雪崩?

缓存层由于某些原因(大量缓存集中在某一个时间段失效缓存宕机)不能提供服务,于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的情况。

雪崩原因?

  1. 大量缓存集中在某一个时间段失效。
  2. 缓存服务宕机。

雪崩后果?

存储层调用量暴增,可能会造成存储层级联宕机。

如何解决?

  1. 保证缓存层服务高可用性(Redis Sentinel,Redis Cluster)
  2. 依赖隔离组件为后端限流并降级
  3. 提前演练
    演练缓存层宕掉后,应用以及后端的负 载情况以及可能出现的问题,在此基础上做一些预案设定。
  4. 缓存失效时间分散开(失效时间基础上加随机数),或者永不过期

穿透

何为穿透?

缓存穿透是指查询一个根本不存在的数据。一般是:
缓存层不命中 ==>存储层不命中,不将空结果写回缓存==>返回空结果。
不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义

穿透后果?

使后端存储负载加大,甚至GG。

穿透原因?

  1. 自身业务代码或者数据出现问题。(粗暴点说,你每次返回uid的时候都在后年拼接上“qqq”,那业务方每次用uid获取用户信息肯定找不到数据。)
  2. 恶意攻击、爬虫。(有人搞事情)

如何解决?

  1. 缓存空对象(存储层不命中后,仍然将空对象保留到缓存层中)
    1.1问题:需要更多的内存空间
    空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间(如果是攻击,问题那就严重了,一会给你写满了),一般针对这种情况我们的会针对这类数据设置一个较短的过期时间,让其自动剔除
    1.2 问题:缓存层和存储层数据的不一致
    你这边缓存完了,完事存储层把数据加上了,就有一个数据不一致的窗口期。数据更改时主动删除相应缓存
  2. 布隆过滤器
    有兴趣可以自己去研究就下这东西。个人觉着,一般咱们的业务用上边那个。
    2.1适用于数据命中不高、数据相对固定、实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。

击穿

何为击穿?

某条缓存数据失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。

击穿原因?

1.当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
2.重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的 SQL、多次IO、多个依赖等。

击穿后果?

存储端负载加大,甚至可能会让其崩溃。

如何解决?

  1. 互斥锁
    只允许一个线程重建缓存,其他线程等待重建缓存的线程执行 完,重新从缓存获取数据即可。
    优:思路简单。较好地降低后端存储负载。一致性上做得 比较好。
    缺:死锁或者线程阻塞如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险。
  2. 热点数据永不过期
    2.1 不设置过期时间
    2.2 (定时刷新)为每个value设置一个逻辑过期时间,当发现超过逻 辑过期时间后,会使用单独的线程去构建缓存。
    优:用不过期,不存在热点KEY导致的问题。
    缺:代码复杂,实现困难。存在数据不一样的情况。

无底洞(这玩意说的是在集群里)

何为无底洞?

缓存的结点已经很多了。这时候你在增加新的缓存结点。发现性能不但没有好转反而下降了。

无底洞原因?

  1. 批量操作涉及的网络操作次数变多。
    键值数据库由于通常采用哈希函数将 key映射到各个节点上。添加大量节点做水平扩容,导致键值分布到更多的节点上。而批量操作通常需要从不同节点上获取。例如一次mget操作需要访问多个Redis节点, 需要多次网络时间。
  2. 网络连接数变多,对节点的性能也有一定影响。

如何解决?

  1. 常见的IO优化思路:
    1.1 命令本身的优化,例如优化SQL语句。
    1.2 减少网络通信次数。
    1.3 降低接入成本,例如客户端使用长连/连接池、NIO等。
  2. 减少网络通信次数(批量操作解决方案):
    2.1串行命令:客户端n次get:n次网络+n次get命令本身。
    Redis Cluster:无法使用mget命令一次性获取。
    优:实现起来比较简单。
    缺:时间复杂度较高。大量keys超时严重。
    2.2串行IO:node次网络时间+n次命令时间。
    Redis Cluster:使用CRC16算法计算出散列值,再取对16383的余数就可以算出slot值。
    Redis Cluster:Smart客户端会保存slot和节点的对应关系。
    优:实现起来比较简单。
    缺:时间复杂度较高。大量nodes也会超时严重。
    可以得到得到每个节点的key子列表,然后分别对每个结点执行批量操作。
    2.3并行IO
    将方案2中的最后一步改为多线程执行,网络次数虽然还是节点个数,但由于使用多线程网络时间变为O(1)。
    优:利用编程特性,时间取决于最慢的线程。
    缺:增加编程复杂度。多线程并发,出现问题定位也会比较难。
    2.4hash_tag实现:1次网络时间+n次命令时间
    Redis Cluster:的hash_tag功能,它可以将多个key强制分配到一个节点上。
    优:性能较好。
    缺:业务维护成本高。容易出现数据倾斜。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容