背景
在实际使用Redis
中可能会发现一个问题:删除数据后,内存占用率依然很高。这是因为删除数据后Redis
释放的内存空间会由内存分配器管理,并不会立即返回给操作系统,所以操作系统仍然记录着给Redis
分配了大量内存。这往往伴随着一个潜在的风险:Redis
释放的内存空间可能并不是连续的,这些不连续的内存空间很可能处于一种闲置的状态。这就会导致Redis
无法使用这些释放的空闲空间来保存数据,这种情况不仅会减少Redis
可保存的数据量,还会降低Redis
对机器内存的使用率。
Redis
内存碎片的形成Redis
内存碎片的形成可能由两方面引起:一个是操作系统的内存分配机制,另一个是Redis
的负载特性。
内存分配器的分配策略决定了操作系统无法做到按需分配。这是因为内存分配器一般是按固定大小来分配内存的,而不是完全按照应用程序申请的内存空间大小来给程序分配内存的。Redis
可以使用libc
、jemalloc
、tcmalloc
多种内存分配器来分配内存,默认使用jemalloc
。jemalloc
的分配策略之一是按照固定的大小划分内存空间,比如8字节、16字节、32字节、48字节等。当程序申请的内存大小最接近某个固定值时,jemalloc
会给它分配相应大小的空间。如果Redis
每次向分配器申请的内存大小不一样,那么这种分配方式就会形成内存碎片。
Redis
的负载特征在业务中,我们会对键值对进行修改和删除等操作,产生对内存空间的申请和释放操作。如果修改后的键值对变大或变小了,就需要占用额外的内存空间或者释放不用的内存空间,或者删除的键值对不再需要内存空间了,此时会把内存空间释放出来,形成空闲的内存空间。
可以用info memory
命令来查看Redis
的内存状态,执行结果如下所示:
127.0.0.1:6379> info memory
# Memory
// Redis为了保存数据实际申请使用的内存空间,单位为字节
used_memory:866832
// 用户数据所占用的内存空间,也就是缓存数据的大小
used_memory_human:846.52K
// Redis内存使用的峰值
used_memory_rss:4120576
// 用户缓存数据的峰值大小
used_memory_rss_human:3.93M
used_memory_peak:1218808
used_memory_peak_human:1.16M
used_memory_peak_perc:71.12%
used_memory_overhead:824640
used_memory_startup:803352
used_memory_dataset:42192
used_memory_dataset_perc:66.47%
allocator_allocated:897960
allocator_active:1159168
allocator_resident:3600384
total_system_memory:4122103808
total_system_memory_human:3.84G
// 执行Lua脚本所占用的内存空间
used_memory_lua:38912
used_memory_lua_human:38.00K
used_memory_scripts:200
used_memory_scripts_human:200B
number_of_cached_scripts:1
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.29
allocator_frag_bytes:261208
allocator_rss_ratio:3.11
allocator_rss_bytes:2441216
rss_overhead_ratio:1.14
rss_overhead_bytes:520192
// 内存碎片率
mem_fragmentation_ratio:4.99
mem_fragmentation_bytes:3294760
mem_not_counted_for_evict:480
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:20504
mem_aof_buffer:512
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
内存碎片率的计算公式如下:
mem_fragmentation_ratio = used_memory_rss / used_memory
内存碎片率mem_fragmentation_ratio
大于且小于1.5是比较合理的,造成内存碎片的原因是无法避免的。mem_fragmentation_ratio
大于1.5时,表明内存碎片率超过了50%,这时就需要采取一些措施来降低内存碎片率。
在Redis 4
版本之前,我们只能重启Redis
服务,但是这有可能出现下面两个问题:
在Redis 4
版本之后,Redis
自身提供了一种内存碎片自动清理的方法,在规定的范围内进行内存空间的合并。
相关参数如下: