雪崩
何为雪崩?
缓存层由于某些原因(大量缓存集中在某一个时间段失效,缓存宕机)不能提供服务,于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的情况。
雪崩原因?
- 大量缓存集中在某一个时间段失效。
- 缓存服务宕机。
雪崩后果?
存储层调用量暴增,可能会造成存储层级联宕机。
如何解决?
- 保证缓存层服务高可用性(Redis Sentinel,Redis Cluster)
- 依赖隔离组件为后端限流并降级
-
提前演练
演练缓存层宕掉后,应用以及后端的负 载情况以及可能出现的问题,在此基础上做一些预案设定。 - 缓存失效时间分散开(失效时间基础上加随机数),或者永不过期
穿透
何为穿透?
缓存穿透是指查询一个根本不存在的数据。一般是:
缓存层不命中 ==>存储层不命中,不将空结果写回缓存==>返回空结果。
不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。
穿透后果?
使后端存储负载加大,甚至GG。
穿透原因?
- 自身业务代码或者数据出现问题。(粗暴点说,你每次返回uid的时候都在后年拼接上“qqq”,那业务方每次用uid获取用户信息肯定找不到数据。)
- 恶意攻击、爬虫。(有人搞事情)
如何解决?
-
缓存空对象(存储层不命中后,仍然将空对象保留到缓存层中)
1.1问题:需要更多的内存空间。
空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间(如果是攻击,问题那就严重了,一会给你写满了),一般针对这种情况我们的会针对这类数据设置一个较短的过期时间,让其自动剔除。
1.2 问题:缓存层和存储层数据的不一致
你这边缓存完了,完事存储层把数据加上了,就有一个数据不一致的窗口期。数据更改时主动删除相应缓存 -
布隆过滤器
有兴趣可以自己去研究就下这东西。个人觉着,一般咱们的业务用上边那个。
2.1适用于数据命中不高、数据相对固定、实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。
击穿
何为击穿?
某条缓存数据失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。
击穿原因?
1.当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
2.重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的 SQL、多次IO、多个依赖等。
击穿后果?
存储端负载加大,甚至可能会让其崩溃。
如何解决?
-
互斥锁
只允许一个线程重建缓存,其他线程等待重建缓存的线程执行 完,重新从缓存获取数据即可。
优:思路简单。较好地降低后端存储负载。一致性上做得 比较好。
缺:死锁或者线程阻塞如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险。 -
热点数据永不过期
2.1 不设置过期时间
2.2 (定时刷新)为每个value设置一个逻辑过期时间,当发现超过逻 辑过期时间后,会使用单独的线程去构建缓存。
优:用不过期,不存在热点KEY导致的问题。
缺:代码复杂,实现困难。存在数据不一样的情况。
无底洞(这玩意说的是在集群里)
何为无底洞?
缓存的结点已经很多了。这时候你在增加新的缓存结点。发现性能不但没有好转反而下降了。
无底洞原因?
- 批量操作涉及的网络操作次数变多。
键值数据库由于通常采用哈希函数将 key映射到各个节点上。添加大量节点做水平扩容,导致键值分布到更多的节点上。而批量操作通常需要从不同节点上获取。例如一次mget操作需要访问多个Redis节点, 需要多次网络时间。 - 网络连接数变多,对节点的性能也有一定影响。
如何解决?
- 常见的IO优化思路:
1.1 命令本身的优化,例如优化SQL语句。
1.2 减少网络通信次数。
1.3 降低接入成本,例如客户端使用长连/连接池、NIO等。 - 减少网络通信次数(批量操作解决方案):
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强制分配到一个节点上。
优:性能较好。
缺:业务维护成本高。容易出现数据倾斜。