比如程序申请一个20字节的内存,内存分配器会分配一个32字节的内存空间,这么做是为了减少分配次数。
redis的info memory
命令可以帮助我们判断当前实例是否存在内存碎片
INFO memory
# Memory
used_memory:1073741736 ## redis实际申请的内存空间大小
used_memory_human:1024.00M
used_memory_rss:1997159792 ## OS分配给redis的物理内存空间,其中包含内存碎片
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86
指标mem_fragmentation_ratio:1.86 表示当前的内存碎片率,
计算公式为mem_fragmentation_ratio = used_memory_rss/ used_memory
所以,mem_fragmentation_ratio=1应该是最理想的情况
产生内存碎片不可避免,那么内存碎片率达到多少需要进行清理呢,这里有个经验阈值
当然还有可能存在一种情况,即内存碎片率 小于1:
这时候就说明used_memory_rss < used_memory,即操作系统分配给redis的物理内存 小于 redis实际存储数据的内存。这种情况下,就会存在一部分redis的数据被换到了swap中,当redis访问这部分数据时就会有严重的性能问题,需要考虑进行扩容或者集群改造了。
Redis 4.0-RC3 + 版本提供了内存碎片自动清理的办法,其基本思想是“搬家让位,合并空间”
config set activedefrag yes
这里我设置activedefrag
参数时遇到下面的报错
127.0.0.1:6379> config set activedefrag yes
(error) DISABLED Active defragmentation cannot be enabled: it requires a Redis server compiled with a modified Jemalloc like the one shipped by default with the Redis source distribution
原因:Redis使用的内存分配器可以是libc、jemalloc、tcmalloc,源码编译安装时默认是jemalloc,自动清理内存碎片的功能需要该redis的内存分配器是jemalloc时才能启用。
我这边的内存分配器是libc
$ redis-cli info memory|grep mem_allocator
mem_allocator:libc
解决:需要重新编译安装。生产环境的话,如果必须要开自动清理功能,主从或集群架构可以通过切主来避免业务影响,单机的话则需要做好数据备份后安排停机窗口然后重编译。
启用后需要同时满足下面2个参数的设置条件时才会触发自动清理
active-defrag-ignore-bytes 100mb # 默认100MB,表示内存碎片空间达到100MB时
active-defrag-threshold-lower 10 # 默认10,表示内存碎片空间占OS分配给redis的物理内存空间的比例达到10%时
redis是单进程模型,内存碎片自动清理是通过==主线程操作==的,也会消耗一定的CPU资源,为了避免自动清理降低Redis的处理性能,如下两个参数可以控制清理动作消耗的CPU时间比例的上下限。
active-defrag-cycle-min 5 : 默认5,表示自动清理过程所用 CPU 时间的比例不低于5%,保证清理能正常开展;
active-defrag-cycle-max 75: 默认75,表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。
除了开启内存碎片自动清理策略,redis从4.0.0版本后也支持手动清理内存碎片,通过如下命令实现
127.0.0.1:6379> memory purge
OK
需要注意的是,该清理命令也只当redis的内存分配器是==jemalloc==时才能生效
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。