Redis内存碎片:深度解析与优化策略

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis内存碎片主要是因为Redis数据存储和回收过程中的内存管理问题导致的

本文已收录至GitHub,推荐阅读 👉 Java随想录

微信公众号:Java随想录

原创不易,注重版权。转载请注明原作者和原文链接

在我们探究和优化Redis性能的过程中,「Redis内存碎片」是一个不可忽视的话题。

这篇文章将深入研究这个看似微不足道,但实际上对Redis运行效率产生重要影响的问题。首先,让我们揭开Redis内存碎片的神秘面纱,理解它的本质及其为何成为我们必须面对的挑战。

内存碎片如何产生的

Redis内存碎片主要是因为Redis数据存储和回收过程中的内存管理问题导致的。

Redis分配内存时,会根据需要申请一段连续的内存空间。但当Redis删除或修改数据时,释放的内存空间并不一定能被立即重新利用,尤其是当这些空闲内存空间大小不一致时,就可能导致内存碎片的出现。

为了提高内存使用的效率,Redis内部使用内存分配器来对内存的申请和释放进行管理。Redis使用的内存分配器默认是「jemalloc」。

而内存分配器是按照固定大小来分配内存的,并不是完全按照程序申请的内存大小来进行分配。

比如程序申请一个20字节的内存,内存分配器会分配一个32字节的内存空间,这么做是为了减少分配次数。redis会申请不同大小的内存空间来存储不同业务不同类型的数据,由于内存按照固定大小分配且会比实际申请的内存要大一些,这个过程中会产生内存碎片。

举个生活中的例子,帮助大家理解:

假设你正在整理一间图书馆。图书馆的书架就像是Redis储存数据的内存空间。每本书都代表不同大小的数据。刚开始时,你把所有的书都按照大小放好。小书在一侧,大书在另一侧。这样你可以有效地利用书架的空间,也方便找书。

但是,如果你需要移除一些书(删除某些数据),然后又加入新的书(新增数据),就可能出现问题了。例如,你移除了一些大书,把它们的位置空出来,然后把新的小书放进去。这样下来,原本属于大书的空间,现在只被小书部分占用,剩余的空白就成了“内存碎片”。

又或者你有一堆新的大书要放,但书架上只有分散的小书的空位,无法容纳这些大书。这个时候你可能需要重新排列整个书架(类似于Redis的内存整理)去腾出连续的大片空间来摆放这些新的大书。

总结来说:当数据不断删除和新增时,内存中空出的位置可能无法完全匹配新数据的大小,导致产生未被利用的“碎片”空间,这就是内存碎片。

内存分配器

Redis 使用内存分配器来管理其在运行期间需要使用的内存资源。可以是libc、jemalloc、tcmalloc。默认是jemalloc。

要指定 Redis 使用哪个内存分配器,你需要在编译 Redis 时做出选择。通常在执行 make 命令时可以通过 MALLOC 参数来指定。例如,如果你想使用 jemalloc,你可以像这样编译 Redis:make MALLOC=jemalloc

jemalloc在64位系统中,将内存空间划分为小、大、巨大三个范围。每个范围内又划分了许多小的内存块单位,存储数据的时候,会选择大小最合适的内存块进行存储。

jemalloc划分的内存单元如下图所示:

也就是说Redis是以指定大小的块为单位进行连续内存分配的,而不是按需分配的,Redis 会根据申请的内存最接近的固定值分配相应大小的空间。

这就像你有不同的箱子,为了装东西,你需要找一个体积最接近的箱子来装。但是装进去后,你发现还有空间可以放一些小东西,就无需再找箱子了。

但是,这种分配空间的方式会带来一定程度的内存碎片。我们可以把固定大小的划分空间看成不同体积的箱子,每种箱子里的空间不同程度上都会有剩余。这些剩余的空间就是内存碎片。

怎么看是否有内存碎片

我们登陆到Redis服务器上,执行以下命令,这会返回一段描述Redis内存使用情况的文本。

redis> info memory

我们会看到类似如下的信息:

在这里,我们主要关注的是名为mem_fragmentation_ratio的字段,它显示了Redis内存碎片的比例。

如果mem_fragmentation_ratio大于1,那就表示存在内存碎片。这个值越大,内存碎片就越多。如果该值非常接近1或者小于1,则表示内存碎片很少或者没有。

计算公式为:

mem_fragmentation_ratio = used_memory_rss / used_memory

其中:

  • used_memory_rss:代表Redis进程占用的总物理内存大小(包括码区、数据区和堆栈等),单位是字节。
  • used_memory:代表Redis分配器申请的内存总量,也就是从操作系统角度看进程实际使用的虚拟内存空间,单位是字节。

碎片率的意义

mem_fragmentation_ratio的不同值,说明不同的情况。

  • 大于1:说明内存有碎片,通常在1到1.5之间是正常的。
  • 大于1.5:说明内存碎片率比较大,需要考虑是否要进行内存碎片清理,要引起重视。
  • 小于1:说明已经开始使用交换内存,也就是使用硬盘了,正常的内存不够用了,需要考虑是否要进行内存的扩容,使用swap是相当影响性能的。

清理内存碎片

低于4.0-RC3版本的Redis

Redis 4.0-RC3之前的版本并没有内置的内存碎片整理工具。如果你想要清理内存碎片,可以通过重启的方式。

当Redis重新启动时,它会通过RDB持久化功能将数据存储到磁盘,然后再从磁盘加载数据到内存,这个过程可以有效地清理内存碎片。但这种方法会导致服务的临时中断。

高于4.0-RC3版本的Redis

Redis4.0-RC3版本开始,引入了active-defrag 特性。可以在不重启的情况下,自动进行碎片清理。

开启配置如下,此选项的默认值是关闭的,激活碎片整理可能会占据一些 CPU 时间。

redis> config set activedefrag yes

注意:自动清理内存碎片的功能需要该Redis的内存分配器是jemalloc时才能启用

启用后需要同时满足下面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 > memory purge

需要注意的是,该命令会阻塞主进程,并且目前也仅实现了jemalloc作为内存分配器的内存统计,对其他分配器暂不支持。

本篇文章到这就结束了。在我们深入研究Redis内存碎片管理和优化策略后,可以明确一点:理解并合理处理内存碎片化对于保证Redis的性能及稳定性至关重要。

不论是进行内存分配策略的调整,还是使用适当的数据结构,都是对Redis内存管理的优化。

同时,定期的监控和审视也是必不可少的步骤。希望本文能为你在处理Redis内存碎片问题上提供一些有价值的启示。记住,每一个优秀的工程师都应该以理解其使用的工具为荣。让我们持续关注和优化Redis,使其更好地服务于我们的项目,推动业务的发展。


感谢阅读,如果本篇文章有任何错误和建议,欢迎给我留言指正。

老铁们,关注我的微信公众号「Java 随想录」,专注分享Java技术干货,文章持续更新,可以关注公众号第一时间阅读。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
12天前
|
SQL 安全 网络安全
构筑网络长城:网络安全漏洞解析与防御策略
【4月更文挑战第30天】 在数字化时代,网络安全已成为维护信息完整性、确保数据流通安全和保障用户隐私的关键。本文将深入探讨网络安全的核心问题——安全漏洞,并分享关于加密技术的最新进展以及提升个人和企业安全意识的有效方法。通过对常见网络威胁的剖析,我们旨在提供一套综合性的网络防御策略,以助力读者构建更为坚固的信息安全防线。
|
1天前
|
NoSQL Linux Redis
Redis内存分析工具RDR
Redis内存分析工具RDR
11 1
|
3天前
|
机器学习/深度学习 算法 Linux
xenomai内核解析--实时内存管理--xnheap
Xenomai是一个实时操作系统(RTOS)层,用于Linux,旨在提供确定性的任务调度和服务。其内存管理机制包括一个名为xnheap的内存池,确保内存分配和释放的时间确定性,以满足硬实时系统的严格需求。
10 0
xenomai内核解析--实时内存管理--xnheap
|
4天前
|
缓存 Java 编译器
JMM内存模型 volatile关键字解析
JMM内存模型 volatile关键字解析
10 0
|
4天前
|
存储 NoSQL Java
熟悉Redis吗,那Redis的过期键删除策略是什么
对于Redis,我们业务开发一般都只关心Redis键值对的查询、修改操作,可能因为懒或者只想能用就行,呵呵。很少关心键值对存储在什么地方、键值对过期了会怎么样、Redis有没什么策略处理过期的键、Redis处理过期键又有什么作用?但这些问题却是Java程序员在Redis上进阶的必备知识,不要埋怨Java要学习的系统知识为什么这么多,因为这些确确实实是进阶的程序员所必须掌握的。我们往下看看~
25 2
熟悉Redis吗,那Redis的过期键删除策略是什么
|
4天前
|
安全 Java Android开发
构建高效Android应用:采用Kotlin进行内存优化的策略
【5月更文挑战第8天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,合理管理内存资源是确保应用流畅运行的关键因素之一。近年来,Kotlin作为官方推荐的开发语言,以其简洁、安全和互操作性的特点受到开发者青睐。本文将深入探讨利用Kotlin语言特性,通过具体策略对Android应用的内存使用进行优化,旨在帮助开发者提高应用性能,减少内存消耗,避免常见的内存泄漏问题。
8 0
|
5天前
|
存储 缓存 监控
快速掌握Redis优化要点,告别性能瓶颈!
# Redis优化指南 了解如何提升Redis性能,从读写方式(整体与部分)、KV size、Key数量、读写峰值、命中率、过期策略、平均穿透加载时间、可运维性、安全性等方面着手。选择合适的读写策略,如只整体读写或部分读写变更,优化KV size避免过大或差异过大,合理管理Key数量,应对不同读写峰值,监控命中率并持续优化,设置智能过期策略,减少平均穿透加载时间,确保高可运维性并强化安全性。一起探索Redis的性能潜力!
164 4
|
7天前
|
缓存 监控 NoSQL
Redis缓存雪崩及应对策略
缓存雪崩是分布式系统中一个常见但危险的问题,可以通过合理的缓存策略和系统设计来降低发生的概率。采用多层次的缓存架构、缓存预热、合理的缓存失效时间等措施,都可以有效应对缓存雪崩,提高系统的稳定性和性能。在实际应用中,及时发现并解决潜在的缓存雪崩问题,是保障系统可用性的关键一环。
38 14
|
10天前
|
缓存 NoSQL Java
优化Redis缓存:解决性能瓶颈和容量限制
优化Redis缓存:解决性能瓶颈和容量限制
21 0
|
12天前
|
机器学习/深度学习 自动驾驶 安全
深入理解操作系统内存管理:策略与实现基于深度学习的图像识别技术在自动驾驶系统中的应用
【4月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效、稳定运行的关键组成部分。本文将深入探讨操作系统中内存管理的多种策略及其实现机制,包括但不限于分页、分段和段页式结合等技术。我们将剖析内存分配的原理,讨论虚拟内存技术的实现以及它如何提供更大的地址空间并允许内存的交换。同时,我们还会涉及内存保护机制,它们是如何防止程序访问未授权的内存区域。最后,文中将对现代操作系统如Linux和Windows中的内存管理实践进行比较分析,以期给读者提供全面而深入的理解和参考。 【4月更文挑战第30天】 随着人工智能技术的飞速发展,深度学习已经

推荐镜像

更多