Redis的内存淘汰策略及LRU算法

Redis过期的数据是怎么删除的?

Redis对过期key的删除方式有两种。

  1. 惰性删除。当key过期时先不删除,到下次获取该key的时候,再进行判断,如果发现已经过期,则将该key删除。并且返回NULL。
  2. 定期删除。Redis后台会有一个定时任务,定时增量的迭代数据,找到过期的key进行删除。每次删除一部分。

Redis目前使用的方式是 惰性删除 + 定期删除 混合使用。

为什么Redis要定时增量的删除过期的key?

​ 很简单,因为Redis是单线程的,所以当Redis在扫描过期数据进行删除的时候,由客户端发来的操作是处于阻塞状态。如果Redis中有大量的过期数据,那么这个删除过程可能要消耗很长的时间。这就会导致Redis的性能降低。所以,在每次主动删除的时候,只删除一部分,后续再从上次删除的位置继续向后查找并删除。这样可以避免Redis写操作的阻塞。

Redis内存满了怎么办?

在Redis的配置文件中,可以配置maxmemory,这个配置的作用是指定Redis的最大内存。

maxmemory <bytes>

当Redis中的数据超过指定的内存大小后,会触发内存淘汰。清理掉一部分key,如果空间仍然不足,会抛出OOM异常。

下面这段代码,将最大内存设置为1byte,演示了内存不足导致的OOM的情况

127.0.0.1:6379> config set maxmemory 1
OK
127.0.0.1:6379> 
127.0.0.1:6379> set k1 123132
(error) OOM command not allowed when used memory > 'maxmemory'.
127.0.0.1:6379> 

如果不设置内存大小,或者设置了内存大小为0,那么在64位操作系统下,Redis不限制内存大小;在32位操作系统下,Redis限制最大内存为3GB。

可以通过 info memory命令来查看Redis内存的使用情况。

127.0.0.1:6379> 
127.0.0.1:6379> info memory
# Memory
used_memory:887512		# 已使用内存
used_memory_human:866.71K # 已使用内存,换算成可读的单位
used_memory_rss:2977792
used_memory_rss_human:2.84M
used_memory_peak:945720	# 内存使用峰值
used_memory_peak_human:923.55K	# 内存使用峰值,换算成可读的单位
used_memory_peak_perc:93.85%
used_memory_overhead:844992
used_memory_startup:803224
used_memory_dataset:42520
used_memory_dataset_perc:50.45%
allocator_allocated:941280
allocator_active:1220608
allocator_resident:3502080
total_system_memory:1019572224	# 操作系统可用内存大小
total_system_memory_human:972.34M	# 操作系统可用内存大小,换算成可读的单位
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0					# 当前配置的Redis最大内存
maxmemory_human:0B
maxmemory_policy:noeviction	# 当前配置的内存回收策略
allocator_frag_ratio:1.30
allocator_frag_bytes:279328
allocator_rss_ratio:2.87
allocator_rss_bytes:2281472
rss_overhead_ratio:0.85
rss_overhead_bytes:-524288
mem_fragmentation_ratio:3.52
mem_fragmentation_bytes:2131296
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:41008
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
127.0.0.1:6379> 

上面说到,当Redis中的数据超过配置的最大内存时,会触发内存淘汰。

那么Redis具体是以什么方式去删除原来的数据,从而为新数据腾出空间来呢?

这个就要看我们具体配置了哪一种内存淘汰策略。

内存淘汰策略

Redis目前共有8种淘汰策略,其中2种是Redis 5之后新增的,在Redis 5之前,只有6种。

noeviction不删除任何数据,内存满后, 无法继续写入
allkeys-lru所有key中,最近最久没有访问的
allkeys-lfu所有key中,最近访问频率最少的
allkeys-random从所有的key中,随机选择
volatile-lru从设置了超时时间的key中,挑选最近最久没有访问的
volatile-lfu从设置了超时时间的key中,挑选最近访问频率最少的
volatile-random从设置了超时时间的key中,随机选择
volatile-ttl从设置了超时时间的key中,挑选越早到期的

可以通过配置文件中的 maxmemory-policy 配置内存淘汰策略。如果不进行配置,默认的是noeviction,不淘汰任何数据,当内存满后,无法继续写入。

maxmemory-policy noeviction

我们在内存淘汰策略中看到不管是针对所有的key,还是设置了过期时间的key,都有一个xxx-lru的策略,这种策略是基于LRU算法,来挑选最近最久没有访问的key进行删除。

下面来了解以下LRU算法。

LRU算法

LRU是Least Recently Used的缩写,及最近最少使用页面置换算法。是操作系统中的一个概念。目的是淘汰最长时间未被使用的页面。

LRU的设计原理就是,当数据在最近一段时间经常被访问,那么它在以后也会经常被访问。这就意味着,如果经常访问的数据,我们需要让其能够快速命中,而不常访问的数据,我们在容量超出限制内,要将其淘汰。

当Redis进行LRU淘汰时,Redis会基于server.maxmemory_samples配置选取固定数目的key,然后比较它们的lru访问时间,然后淘汰最近最久没有访问的key。

LRU和LFU的区别

其实在内存淘汰策略中,还有一种基于LFU算法的方式。

LFU是最近最不常用页面置换算法,淘汰一定时期内被访问次数最少的页。

LRU看重访问时间,LFU看重访问次数。

内存淘汰策略的使用

如果Redis只是作为缓存使用,那么可以使用 allkeys-xxx 淘汰策略,从所有key中进行挑选,因为缓存允许数据丢失。

如果Redis是作为数据库来使用的,或者说需要持久化数据,那么可以使用 volatile-xxx 淘汰策略,只从设置了过期时间的key中进行挑选。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值