redis key 过期处理和内存淘汰机制

(1)redis删除过期key

1、定时删除

设置键的过期时间,创建定时器,一旦过期时间来临,就立即对键进行操作。

这种对内存是友好的,但是对 CPU 的时间是最不友好的,特别是在业务繁忙,过期键很多的时候,删除过期键这个操作就会占据很大一部分 CPU 的时间。

要知道 Redis 是单线程操作,在内存不紧张而 CPU 紧张的时候,将 CPU 的时间浪费在与业务无关的删除过期键上面,会对 Redis 的服务器的响应时间和吞吐量造成影响。

另外,创建一个定时器需要用到 Redis 服务器中的时间事件,而当前时间事件的实现方式是无序链表,时间复杂度为 O(n),让服务器大量创建定时器去实现定时删除策略,会产生较大的性能影响,所以,定时删除并不是一种好的删除策略。

2、惰性删除

与定时删除相反,惰性删除策略对 CPU 来说是最友好的,程序只有在取出键的时候才会进行检查,是一种被动的过程。

与此同时,惰性删除对内存来说又是最不友好的,一个键过期,只要不再被取出,这个过期键就不会被删除,它占用的内存也不会被释放。

很明显,惰性删除也不是一个很好的策略,Redis 是非常依赖内存和较好内存的,如果一些长期键长期没有被访问,就会造成大量的内存垃圾,甚至会操成内存的泄漏。

在对执行数据写入时,通过 expireIfNeeded 函数对写入的 Key 进行过期判断。

其中 expireIfNeeded 在内部做了三件事情,分别是:

  • 查看 Key 是否过期。
  • 向 Slave 节点传播执行过去 Key 的动作。
  • 删除过期 Key。

3、定期删除

上面两种删除策略,无论是定时删除和惰性删除,这两种删除方式在单一的使用上都存在明显的缺陷,要么占用太多 CPU 时间,要么浪费太多内存。

定期删除策略是前两种策略的一个整合和折中:

  • 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时间和频率来减少删除操作对 CPU 时间的影响。
  • 通过合理的删除执行的时长和频率,来达到合理的删除过期键。

定期删除+惰性删除

所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。假设redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过期key上了。注意,这里可不是每隔100ms就遍历所有的设置过期时间的key,那样就是一场性能上的灾难。实际上redis是每隔100ms随机抽取一些key来检查和删除的。

定期删除

1)定时任务在每个数据库空间随机检测20个键,当发现过期时,删除对应的键

2)如果超过检查数25%的键过期,循环执行回收逻辑直到不足25%或运行超时为止,慢模式下超时时间为25毫秒

3)如果之前回收的键逻辑超时,则在redis触发内部事件之前再次以快模式运行回收过期键任务,快模式下超时时间为1毫秒且2秒内只能运行一次

4)快慢两种模式内部删除逻辑相同,只是执行的超时时间不同

 

但是问题是,定期删除可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

通过上述两种手段结合起来,保证过期的key一定会被干掉。

 

很简单,就是说,你的过期key,靠定期删除没有被删除掉,还停留在内存里,占用着你的内存呢,除非你的系统去查一下那个key,才会被redis给删除掉。

 

但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?

 

答案是:走内存淘汰机制。

 

 

(2)内存淘汰(内存溢出控制策略)

 

如果redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略:

 

redis 10个key,现在已经满了,redis需要删除掉5个key

 

1个key,最近1分钟被查询了100次

1个key,最近10分钟被查询了50次

1个key,最近1个小时倍查询了1次

 

1)noeviction:不淘汰,当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了

2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊

4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)

5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key

6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

 

 

内存优化

1 redis 实际内存消耗主要包括:建值对象、缓冲区内存、内存碎片

2 通过调整 maxmemory 控制redis最大可用内存。当内存使用超出时,根据 maxmemory-policy 控制内存回收策略

3 内存是相对宝贵的资源,通过合理的优化可以有效的降低内存的使用量,内存优化的思路包括:

  • 精简键值对大小,键值字面量精简,使用高效二进制序列工具
  • 使用对象共享池优化小整数对象
  • 数据优先使用整数,比字符串类型更节省空间
  • 优化字符串使用,避免预分配造成的内存浪费
  • 使用 ziplist 压缩编码优化 hash、list等结构,注重效率和空间的平衡
  • 使用 intset 编码优化整合集合
  • 使用 ziplist 编码的 hash 结构降低减小对象链规模

 

对象共享

Redis 在自己的对象系统中构建了一个引用计数方法,通过这个方法程序可以跟踪对象的引用计数信息,除了可以在适当的时候进行对象释放,还可以用来作为对象共享。

举个例子,假使键 A 创建了一个整数值 100 的字符串作为值对象,这个时候键 B 也创建保存同样整数值 100 的字符串对象作为值对象。

那么在 Redis 的操作时:

  • 讲数据库键的指针指向一个现有的值对象。
  • 讲被共享的值对象引用计数加一。

假使,我们的数据库中指向整数值 100 的键不止键 A 和键 B,而是有几百个,那么 Redis 服务器中只需要一个字符串对象的内存就可以保存原本需要几百个字符串对象的内存才能保存的数据。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值