Redis 是如何做内存回收的

😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD
如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。
😊 座右铭:不想当开发的测试,不是一个好测试✌️。
如果感觉博主的文章还不错的话,还请点赞、收藏哦!👍

前言 ❤️

redis是基于内存存储,所以性能比较强,但是单节点的 Redis 内存大小不宜过大,要不然会影响持久化或者主从同步性能,可以在redis.conf配置文件中设置最大内存,maxmemory 1gb,但是当内存使用达到上限时,就无法存储更多数据了,这时该怎么办呢?
在Redis中提供了两种内存回收策略:

  1. 过期策略
  • 在过期策略中会了解到以下内容:
    (1)Rediskey 的 TTL 记录方式:

      在RedisDB中通过一个 Dict 记录每个 Key 的 TTL 时间
    

    (2)过期 key 的删除策略:

      惰性清理:每次查找 key 时判断是否过期,如果过期则删除
      定期清理:定期抽样部分 key,判断是否过期,如果过期则删除。
    

    (3)定期清理的两种模式:

      SLOW 模式执行频率默认为10,每次不超过25ms
      FAST 模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms
    
  1. 淘汰策略
    会了解到八种淘汰策略

过期策略🌟

通过expire命令给 Redis 的 key 配置TTL(存活时间)

127.0.0.1:6379> set num jenny
OK
127.0.0.1:6379> expire num 10 # 设置10s
(integer) 1 
127.0.0.1:6379> get num # 在10s内key存在
"jenny"
127.0.0.1:6379> get num # 当key的TTL到期以后,再次访问则返回的是nil,说明这个key不存在了
(nil)

当 TTL 到期之后,对应的内存得到释放,从而实现内存回收的目的。那么 Redis 是如何知道某个key是否过期的呢?。这就涉及到 Redis 数据库的存储原理,Redis 是基于 key-value 存储的,因此所有的 key、value 都会保存在一个Dict结构中,也可称为 keyspace,如果一个 key 设置了 TTL,则会另外存储在一个 Dict 中,也就是存 key 和它对应的 TTL 存活时间。也就是说,在 Redis 数据库结构体中,有两个 Dict:一个用来记录key-value ,另一个用来记录 key-TTL。这样直接查看 key 对应的TTL即可知道 key 是否到期。

那么,当TTL到期后就立即删除了key吗
不会立即删除,可以采用惰性删除和定期删除。

  • 惰性删除,就是当在访问一个 key 的时候去检查 key 的存活时间,如果存活时间已经过期了才会执行删除。但是这里又有一个问题,如果这个 key 一直没有人访问,那么就一直不会被删除,这样也会占用内存,所以为了解决这个问题,Redis 中提供了一个周期删除的过期策略,就是通过一个定时任务

  • 定期删除:Redis中提供了一个周期删除的过期策略,就是通过一个定时任务,周期性的抽样部分过期的key,然后执行删除,执行周期有两种:

    • Redis 初始化时会设置一个定时任务 serverCron(),按照 server.hz 的频率来清理过期的 key,模式为 SLOW。
      SLOW 模式规则如下:

      (1) 执行频率受 server.hz 影响,默认为10,即每秒执行10次,每个执行周期为100ms

      (2)执行清理耗时不超过一次执行周期的25%

      (3)逐个遍历 db,逐个遍历 db 中的 bucket(哈希表的数组),抽取20个 key 判断是否过期

      (4)如果(执行总时长)没达到时间上限(25ms)并且过期 key 比例大于10%,再进行一次抽样,否则结束

    • Redis 的每个事件循环前会调用 beforceSleep() 函数,清理过期的 key,模式为 FAST(执行的频率比较高,执行时间比较短1ms)
      FAST 模式规则如下(过期key比例小于10%不执行):

      (1)执行频率受 beforeSleep()调用频率影响,但两次 FAST 模式间隔不低于2ms

      (2)执行清理耗时不超过1ms

      (3)逐个遍历 db,逐个遍历 db中的 bucket,抽取20个key判断是否过期

      (4)如果没达到时间上限 (1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

内存淘汰策略🍑

内存淘汰就是当 Redis 内存使用达到设置的阈值时,Redis 主动挑选部分 key 删除以释放更多内存。
那么,

  • Redis什么时候检查内存够不够:当内存被访问的时候就去检查内存。

  • 如何挑选要删除的key?在Redis中提供了八种淘汰策略

(1)noeviction:不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。

在redis.conf中有 maxmemory-policy noeviction 配置

(2)volatile-ttl:对设置了下 TTL 的 key,比较 key 的剩余TTL值,TTL越小越先被淘汰

(3)allkeys-random:对全体 key,随机进行淘汰。也就是直接从 db→dict 中随机挑选

(4)volatile-random:对设置了 TTL 的 key,随机进行淘汰。也就是从 db-sexpires 中随机挑选。

(5)allkeys-lru:对全体 key,基于 LRU 算法进行淘汰(最少最近使用)

(6)volatile-lru:对设置了 TTL 的 key,基于 LRU 算法进行淘汰

(7)allkeys-lfu:对全体 key,基于 LFU 算法进行淘汰(最少频繁使用)

(8)volatile-lfu:对设置了 TTL 的 key,基于LFI算法进行淘汰

要是用 LRULFU算法的话需要知道 key 的使用频率和最近一次的使用时间,在 Redis 的数据都会被封装为RedisObject结构:【了解即可】
在这里插入图片描述
下图是八种淘汰策略的流程图,
在这里插入图片描述
在判断内存策略中是采用 LRU 还是 LFU 时需要判断 key 的值的 TTL,但是在 Redis 中有大量的 key,如果将TTL进行排序是不现实的,eviction_pool 相当于淘汰池,想淘汰一些 key,但是又不想进行遍历,所以从数据库中挑选一些样本,放入eviction_pool 中,然后再整体比较一次,看看他们的TTL和使用频率,基于这个去做淘汰。redis 中总共有16个数据库,从数据库中随机挑选 key,放入 eviction_pool 淘汰池中,但是每种算法的挑选方式不同,所以淘汰方式也不同,但是对于 eviction_pool 淘汰池需要制定一个标准的淘汰标准:按照 key 的某一个值的升序进行排列,值越大的优先淘汰,按什么方法升序排列:LRU:用当前减去最近一次被访问的时间(时间最长越容易被淘汰);LFU:255-频率次数(最越大越容易被淘汰),TTL:用最大时间-剩余时间(值越大越容易被淘汰)计算完成上述方法之后,还需要判断 eviction_pool 淘汰池有没有满,如果满了则需要比较要放入淘汰池的 key 的计算结果比淘汰池的某个值大,这样的key需要放进去,然后把淘汰池的最小的挤出去,然后升序排列。

如果觉的不错的话,别忘记三连哦!

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小曾同学.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值