内存碎片是如何形成的?

其实,内存碎片的形成有内因和外因两个层面的原因。简单来说,内因是操作系统的内存分配机制,外因是 Redis的负载特征。

内因:内存分配器的分配策略

内存分配器的分配策略就决定了操作系统无法做到“按需分配”。这是因为,内存分配器一般是按固定大小 来分配内存,而不是完全按照应用程序申请的内存空间大小给程序分配。

Redis默认使用jemalloc内存分配。

jemalloc的分配策略之一,是按照一系列固定的大小划分内存空间,例如8字节、16字节、32字节、48字 节,..., 2KB、4KB、8KB等。当程序申请的内存最接近某个固定值时,jemalloc会给它分配相应大小的空间。

这样的分配方式本身是为了减少分配次数。例如,Redis申请一个20字节的空间保存数据,jemalloc就会分配32字节,此时,如果应用还要写入10字节的数据,Redis就不用再向操作系统申请空间了,因为刚才分配 的32字节已经够用了,这就避免了一次分配操作。

但是,如果Redis每次向分配器申请的内存空间大小不一样,这种分配方式就会有形成碎片的⻛险,而这正好来源于Redis的外因了。

外因:键值对大小不一样和删改操作

Redis通常作为共用的缓存系统或键值数据库对外提供服务,所以,不同业务应用的数据都可能保存在Redis 中,这就会带来不同大小的键值对。这样一来,Redis申请内存空间分配时,本身就会有大小不一的空间需求。这是第一个外因。

内存分配器只能按固定大小分配内存,所以,分配的内存空间一般都会比申请的空间大 一些,不会完全一致,这本身就会造成一定的碎片,降低内存空间存储效率。

如何判断是否有内存碎片?

INFO 指令

image-20211031110024826

mem_fragmentation_ratio:它表示的就是Redis当前的内存碎片率。其实,就是上面的命令中的两个指标used_memory_rss和used_memory相除的结果。

  • mem_fragmentation_ratio 大于1但小于1.5。这种情况是合理的。这是因为,刚才我介绍的那些因素 是难以避免的。毕竟,内因的内存分配器是一定要使用的,分配策略都是通用的,不会轻易修改;而外因 由Redis负载决定,也无法限制。所以,存在内存碎片也是正常的。
  • mem_fragmentation_ratio 大于 1.5 。这表明内存碎片率已经超过了50%。一般情况下,这个时候, 我们就需要采取一些措施来降低内存碎片率了。

自动内存碎片清理

把activedefrag配置项设置为yes

config set activedefrag yes 

这个命令只是启用了自动清理功能,但是,具体什么时候清理,会受到下面这两个参数的控制。这两个参数分别设置了触发内存清理的一个条件,如果同时满足这两个条件,就开始清理。在清理的过程中,只要有一个条件不满足了,就停止自动清理。

  • active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到100MB时,开始清理;
  • active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给Redis的总空间比例达到10%时,开始清理。
  • active-defrag-cycle-min 25: 表示自动清理过程所用CPU时间的比例不低于25%,保证清理能正常开展;
  • active-defrag-cycle-max 75:表示自动清理过程所用CPU时间的比例不高于75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷⻉阻塞Redis,导致响应延迟升高。
最后修改:2021 年 11 月 21 日
如果觉得我的文章对你有用,请随意赞赏