当前位置: 首页 > article >正文

Redis内存碎片详解

什么是内存碎片?

你可以将内存碎片简单地理解为那些不可用的空闲内存。

举个例子:操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数据的话,就可以被称为内存碎片。

Redis 内存碎片虽然不会影响 Redis 性能,但是会增加内存消耗

为什么会有 Redis 内存碎片?

Redis 内存碎片产生比较常见的 2 个原因:

1、Redis 存储数据的时候向操作系统申请的内存空间可能会大于数据实际需要的存储空间。

以下是这段 Redis 官方的原话:

To store user keys, Redis allocates at most as much memory as the maxmemory setting enables (however there are small extra allocations possible).下面是这段话的一个解释:

这句话的意思是,Redis 会根据配置项 maxmemory 来限制用于存储用户键(即数据)的内存量。当你设置了 maxmemory 参数后,Redis 将不会使用超过这个设定值的内存来存储数据。

然而,需要注意的是,除了用于存储键值对的内存之外,Redis 还会进行一些额外的小量内存分配。这些额外的内存分配主要用于:

  • Redis 内部的数据结构和元数据,如哈希表、跳跃列表等,它们用于高效地管理和索引键。
  • 系统开销,包括但不限于客户端连接信息、命令解析、AOF重写或RDB快照时的缓冲区等。
  • 在执行某些操作时,比如命令的执行过程中,可能会有临时对象被创建,这些也会占用额外的内存。

因此,虽然 maxmemory 设置限制了Redis可以用来存储用户数据的最大内存,但实际使用的总内存量可能会略高于这个值,因为包含了上述提到的额外内存开销。当Redis达到 maxmemory 限制时,它将根据配置的淘汰策略(eviction policy)开始移除一些数据以释放空间。

Redis 使用 zmalloc 方法(Redis 自己实现的内存分配方法)进行内存分配的时候,除了要分配 size 大小的内存之外,还会多分配 PREFIX_SIZE 大小的内存。

zmalloc 方法源码如下(源码地址:https://github.com/antirez/redis-tools/blob/master/zmalloc.c):

void *zmalloc(size_t size) {
   // 分配指定大小的内存
   void *ptr = malloc(size+PREFIX_SIZE);
   if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
   update_zmalloc_stat_alloc(zmalloc_size(ptr));
   return ptr;
#else
   *((size_t*)ptr) = size;
   update_zmalloc_stat_alloc(size+PREFIX_SIZE);
   return (char*)ptr+PREFIX_SIZE;
#endif
}

另外,Redis 可以使用多种内存分配器来分配内存( libc、jemalloc、tcmalloc),默认使用 jemalloc,而 jemalloc 按照一系列固定的大小(8 字节、16 字节、32 字节……)来分配内存的。jemalloc 划分的内存单元如下图所示:

当程序申请的内存最接近某个固定值时,jemalloc 会给它分配相应大小的空间,就比如说程序需要申请 17 字节的内存,jemalloc 会直接给它分配 32 字节的内存,这样会导致有 15 字节内存的浪费。不过,jemalloc 专门针对内存碎片问题做了优化,一般不会存在过度碎片化的问题。

2、频繁修改 Redis 中的数据也会产生内存碎片。

当 Redis 中的某个数据删除时,Redis 通常不会轻易释放内存给操作系统。

这个在 Redis 官方文档中也有对应的原话:

文档地址:Memory optimization | Docs

如何查看 Redis 内存碎片的信息?

使用 info memory 命令即可查看 Redis 内存相关的信息。下图中每个参数具体的含义,Redis 官方文档有详细的介绍:INFO | Docs

Redis 内存碎片率的计算公式:mem_fragmentation_ratio (内存碎片率)= used_memory_rss (操作系统实际分配给 Redis 的物理内存空间大小)/ used_memory(Redis 内存分配器为了存储数据实际申请使用的内存空间大小)

也就是说,mem_fragmentation_ratio (内存碎片率)的值越大代表内存碎片率越严重。

一定不要误认为used_memory_rss 减去 used_memory值就是内存碎片的大小!!!这不仅包括内存碎片,还包括其他进程开销,以及共享库、堆栈等的开销。

很多小伙伴可能要问了:“多大的内存碎片率才是需要清理呢?”。

通常情况下,我们认为 mem_fragmentation_ratio > 1.5 的话才需要清理内存碎片。 mem_fragmentation_ratio > 1.5 意味着你使用 Redis 存储实际大小 2G 的数据需要使用大于 3G 的内存。

如果想要快速查看内存碎片率的话,你还可以通过下面这个命令:

redis-cli -p 6379 info | grep mem_fragmentation_ratio

如何清理 Redis 内存碎片?

Redis4.0-RC3 版本以后自带了内存整理,可以避免内存碎片率过大的问题。

直接通过 config set 命令将 activedefrag 配置项设置为 yes 即可

config set activedefrag yes

具体什么时候清理需要通过下面两个参数控制:

# 内存碎片占用空间达到 500mb 的时候开始清理
config set active-defrag-ignore-bytes 500mb
# 内存碎片率大于 1.5 的时候开始清理
config set active-defrag-threshold-lower 50

通过 Redis 自动内存碎片清理机制可能会对 Redis 的性能产生影响,我们可以通过下面两个参数来减少对 Redis 性能的影响:

# 内存碎片清理所占用 CPU 时间的比例不低于 20%
config set active-defrag-cycle-min 20
# 内存碎片清理所占用 CPU 时间的比例不高于 50%
config set active-defrag-cycle-max 50

另外,重启节点可以做到内存碎片重新整理。如果你采用的是高可用架构的 Redis 集群的话,你可以将碎片率过高的主节点转换为从节点,以便进行安全重启。


http://www.kler.cn/a/449567.html

相关文章:

  • 【点估计】之Python实现
  • web-密码安全口令
  • Docker搭建kafka环境
  • sfnt-pingpong -测试网络性能和延迟的工具
  • Tomcat负载均衡全解析
  • 页面无滚动条,里面div各自有滚动条
  • ue5 pcg(程序内容生成)真的简单方便,就5个节点
  • 基于Python大数据的电影可视化分析系统
  • Jenkins 持续集成部署——Jenkins实战与运维(1)
  • 【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
  • 如何给负载均衡平台做好安全防御
  • 2025前端面试热门题目——计算机网络篇
  • SpringCloud 运用(2)—— 跨服务调度
  • Conda 使用全解析:从入门到精通
  • JavaWeb Servlet的反射优化、Dispatcher优化、视图(重定向)优化、方法参数值获取优化
  • Qt for Python (PySide6)设置程序图标和任务栏图标
  • 【求职面试】大学转专业面试自我介绍模板7篇
  • 解决:websocket 1002 connection rejected 426upgrade required
  • 路径规划之启发式算法之二十:麻雀搜索算法(Sparrow Search Algorithm,SSA)
  • 搭建简易版本的git私有仓库--运用git和gitea
  • 灭屏情况下,飞行模式+静音模式+插耳,播放音乐,电流异常
  • 层序遍历练习
  • 重温设计模式--组合模式
  • 【FFmpeg】解封装 ① ( 封装与解封装流程 | 解封装函数简介 | 查找码流标号和码流参数信息 | 使用 MediaInfo 分析视频文件 )
  • 终章:DevOps实践总结报告
  • 鸿蒙人脸识别