首页 > 其他分享 >缓存雪崩等问题

缓存雪崩等问题

时间:2022-10-06 19:00:07浏览次数:54  
标签:缓存 过期 Redis 问题 雪崩 key 淘汰 内存

缓存雪崩就是在同一段时间内有大量缓存数据失效了(缓存过期了、被内存淘汰策略淘汰了或者 Redis 服务宕机了),然后在这段时间内又有请求想要获取这些数据,因为这些缓存数据已经不在 Redis 中了,所以最终就导致全部请求到了数据库(数据库压力大)。

解决方案:

  1. 将数据分类,不同的分类过期时间不同,或者使用随机过期时间
  2. 超热数据使用永久 key
  3. 对要过期的数据做访问量分析,判断是不是要延长过期时间
  4. redis 集群
  5. 降流、限流
  6. 加锁

缓存击穿

缓存击穿它是热点 key 问题;就是说有一个缓存失效了,但是同一段时间又有一大堆请求想访问这个数据,最终也会导致数据库压力过大。

解决方案:

  1. 预先将某条缓存设置为热点,增加缓存的过期时间
  2. 根据访问量动态调整缓存过期时间
  3. 使用二级缓存,单独保存这些热点数据
  4. 加锁

缓存击穿和缓存雪崩很像,雪崩是一大堆缓存失效了,击穿是几个热点缓存失效了。

缓存雪崩和缓存击穿问题,都是在高并发情况下出现的;缓存失效了,同一时间段又有很多请求访问这些数据,没有在 Redis 中命中,最终导致都会请求到数据库。

缓存穿透

缓存穿透就是访问了数据库中没有的数据,数据库查询不出来数据,就没有办法建立缓存,所以还是会一致请求数据库。

解决方案:

  1. 缓存空对象:当数据库中也不存在数据的时候,在 Redis 中缓存一个空值;但是这样会造成额外的内存消耗和短期的数据不一致
  2. 布隆过滤:在客户端和 Redis 之间增加了布隆过滤器;当布隆过滤中没有数据的时候,就会直接禁止流程继续执行(禁止访问 Redis 和数据库)
  3. 实时监控 key 的命中率:不同的时间段,超过一定阈值就排查问题
  4. key 加密:将请求的数据加密,每天更换加密字符串

布隆过滤器禁止流程继续执行,说明数据 100% 不存在;但是允许流程继续执行并不是 100% 准确的,所以还是有一定的穿透风险。

缓存预热

缓存预热就是防止服务器启动后立马宕机了。

可以在服务启动前,将一些热点数据(日常统计)先添加到 Redis 中,

缓存更新策略

我们将数据保存在缓存和数据库中,当修改了数据库中的数据后,就需要用到缓存更新策略对缓存进行更新;缓存更新策略就是解决缓存一致性问题的。

内存淘汰 超时剔除 主动更新
说明 不用自己维护,利用 Redis 的内存淘汰机制,当 内存不足时 自动淘汰部分数据,然后等到下次查询时候会更新缓存。 给缓存数据 添加 TTL 时间,到期后自动删除缓存,等到下次查询时候会更新缓存。 这个是自己编写业务逻辑,在修改数据库的同时,还要更新缓存。
一致性
因为不确定哪些数据会被淘汰、什么时候被淘汰。
一般
因为更新频率是根据超时时间来的;假设将数据刚写到缓存,数据库就更新了,这会等到超时后才获取数据。

但是这没法保证完全一致,因为有可能程序崩溃。
维护成本
Redis 自动维护

在添加缓存的时候,顺便添加超时时间。

需要对业务进行编码

业务场景:

  • 低一致性需求:使用内存淘汰机制。
  • 高一致性需求:主动更新 + 超时剔除,超时剔除是为了保证程序突然崩溃后,在一段时间后还能更新缓存。

主动更新

主动更新目前有 3 中:

  1. 由缓存的调用者,在更新数据库的同时更新缓存。
  2. 缓存与数据库整合为一个服务,由服务来维护一致性。调用者调用该服务,无需关系缓存一致性问题。
  3. 调用者只操作缓存,让其它线程异步将缓存数据持久化到数据库,最终保持一致。

2、3 维护成本太高,最终还是选择 1。

网上虽然有文章写过一些更新策略,但是我觉得这些策略不需要关注,因为最终还是看业务需求,如果你的业务要求缓存和数据库必须一致,那么每次更新完数据库后必须更新 Redis 的缓存,否则可以等到缓存超时后更新。

key 过期删除策略和内存淘汰策略

key 过期删除策略:

  • 定时删除:给 key 设置过期时间的时候会创建一个关联的定时器,当时间到达时,由定时器自动执行 key 的删除操作;这样做的好处是过期的 key 可以被立即删除,但是会消耗 CPU 降低吞吐量。
  • 惰性删除:访问 key 的时候判断是不是过期,过期就删除 key;这样做的好处是不会占用 CPU 资源,但是会导致过期后 key 还在缓存中。
  • 定期删除:每隔一段时间,随机判断一些 key 是不是过期了,过期了就删除;这样做的好处是减少了 CPU 资源的占用,同时能够清理掉过期的 key,但是执行时常和频率无法确定,和算法又关系。

Redis 选择惰性删除 + 定期删除这两种策略配和使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。

在配置文件 redis.conf 中,可以通过参数 hz <每秒运行多少次> 来设定定期删除时间。

内存淘汰策略

在配置文件 redis.conf 中,可以通过参数 maxmemory <bytes> 来设定最大运行内存,只有在 Redis 的运行内存达到了我们设置的最大运行内存,才会触发内存淘汰策略。 不同位数的操作系统,maxmemory 的默认值是不同的:

  • 在 64 位操作系统中,maxmemory 的默认值是 0,表示没有内存大小限制,那么不管用户存放多少数据到 Redis 中,Redis 也不会对可用内存进行检查,直到 Redis 实例因内存不足而崩溃也无作为。
  • 在 32 位操作系统中,maxmemory 的默认值是 3G,因为 32 位的机器最大只支持 4GB 的内存,而系统本身就需要一定的内存资源来支持运行,所以 32 位操作系统限制最大 3 GB 的可用内存是非常合理的,这样可以避免因为内存不足而导致 Redis 实例崩溃。

在配置文件 redis.conf 中,可以通过参数 maxmemory-policy 来设定内存淘汰策略:

  • volatile-random:随机淘汰一些设置了超时时间的 key
  • volatile-ttl:优先淘汰那些即将过期的 key
  • volatile-lru:淘汰设置了过期时间,但偶尔使用的 key
  • volatile-lfu:淘汰设置了过期时间,但已经不怎么用了的 key
  • allkeys-random:随机淘汰一些 key
  • allkeys-lru:淘汰偶尔使用的 key
  • allkeys-lfu:淘汰已经不怎么使用的 key
  • noeviction:关闭内存淘汰策略,如果关闭会抛出内存溢出

LRU(Least Recently Used):最少使用的,可以理解为这个 key 偶尔被使用,LFU(Least Frequently Used):最不常用的,可以理解为这个 key 已经不怎么用了,random:随机选择一些 key,ttl:优先淘汰那些即将过期的 key。

volatile:只会淘汰设置了过期时间的 key,allkeys:会淘汰所有的 key。

如果使用了 volatile-lru、volatile-lfu、volatile-random 和 volatile-ttl 策略,当没有匹配到任何 key 的时候,它们不会移除任何 key 类似于 noeviction。

标签:缓存,过期,Redis,问题,雪崩,key,淘汰,内存
From: https://www.cnblogs.com/superylg/p/16755467.html

相关文章