20 | 删除数据后,为什么内存占用率还是很高?

191 阅读4分钟

基本概念

  • 基本概念

    • 当数据删除后,Redis 释放的内存空间会由内存分配器管理(不适用java gc的原因之一?),并不会立即返回给操作系统(从操作系统的视角看)
  • 内存不回收存在的问题

    • Redis 释放的内存空间可能并不是连续
    • 不能保存合适的数据
    • 不仅会减少 Redis 能够实际保存的数据量,还会降低 Redis 运行机器的成本回报率

什么是内存碎片?

  • 内存空间闲置,往往是因为操作系统发生了较为严重的内存碎片\

    • 虽然是空着的,但是不满足大部分分配的需求
    • 应用申请的是一块连续地址空间的 N 字节,但在剩余的内存空间中,没有大小为 N 字节的连续空间了\
  • 只有了解了内存碎片的成因,才能对症下药,把 Redis 占用的内存空间充分利用起来,增加存储的数据量\

内存碎片是如何形成的?

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

    • 内存分配器是按照固定大小分配内存,而不是申请多大及多大

    • redis可用的分配器

      • libc\

      • jemalloc 默认\

        • 当程序申请的内存最接近某个固定值时,jemalloc 会给它分配相应大小的空间\

        • 避免了频繁分配

      • tcmalloc

  • 外因:键值对大小不一样和删改操作(不停的扩容与删除)

    • Redis 申请内存空间分配时,本身就会有大小不一的空间需求\

    • [1]分配的内存空间一般都会比申请的空间大一些,不会完全一致\

    • [2]这些键值对会被修改和删除,这会导致空间的扩容和释放

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

\

  • 使用Info命令可以查看内存碎片

    • mem_fragmentation_ratio 表示内存碎片率\

    • 是利用used_memory_rss(从操作系统获取)/used_memory(实际使用)相除的结果

  • 正常的区间

    • mem_fragmentation_ratio 大于 1 但小于 1.5 属于正常情况\

    • mem_fragmentation_ratio 大于 1.5 不可以接收,内存碎片率已经超过了 50%(正常使用的一半)\

  • \

INFO memory 
# Memory used_memory:1073741736 used_memory_human:1024.00M 
used_memory_rss:1997159792 used_memory_rss_human:1.86G … 
mem_fragmentation_ratio:1.86

如何清理内存碎片?

  • 方法1:重启redis

    • 缺点:

      • reids中的数据未持久化,会造成数据丢失
      • 需要通过AOF和RDB进行恢复,无法提供服务
  • 方法2:使用reids自带内存碎片清理 4.0-RC3 版本以后

    • 实现原理:搬家让位,合并空间(类似于GC的复制算法

    • 缺点:碎片清理是有代价的:拷贝数据并释放空间会导致时间开销,阻塞redis的单线程\

    • 优化:Redis 专门为自动内存碎片清理功机制设置的参数

      • 原理:我们可以通过设置参数,来控制碎片清理的开始和结束时机,以及占用的 CPU 比例,从而减少碎片清理对 Redis 本身请求处理的性能影响\

      • 1.Redis 需要启用自动内存碎片清理,可以把 activedefrag 配置项设置为 yes  config set activedefrag yes  

      • 2.active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到 100MB 时,开始清理

      • 3.active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给 Redis 的总空间比例达到 10% 时,开始清理

      • 4.active-defrag-cycle-min 25: 表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展

      • 5.active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高

\

总结

  • 内存碎片优化,可以提升内存利用率,放入更多的元素

    • info memory 命令是一个好工具,可以帮助你查看碎片率的情况\

    • 碎片率阈值是一个好经验,可以帮忙你有效地判断是否要进行碎片清理了\

    • 内存碎片自动清理是一个好方法,可以避免因为碎片导致 Redis 的内存实际利用率降低,提升成本收益率\

\