在我们探究和优化redis性能的过程中,「Redis内存碎片」是一个不可忽视的话题 。
这篇文章将深入研究这个看似微不足道,但实际上对Redis运行效率产生重要影响的问题 。首先,让我们揭开Redis内存碎片的神秘面纱,理解它的本质及其为何成为我们必须面对的挑战 。
文章插图
内存碎片如何产生的Redis内存碎片主要是因为Redis数据存储和回收过程中的内存管理问题导致的 。
Redis分配内存时 , 会根据需要申请一段连续的内存空间 。但当Redis删除或修改数据时 , 释放的内存空间并不一定能被立即重新利用,尤其是当这些空闲内存空间大小不一致时,就可能导致内存碎片的出现 。
为了提高内存使用的效率,Redis内部使用内存分配器来对内存的申请和释放进行管理 。Redis使用的内存分配器默认是「jemalloc」 。
而内存分配器是按照固定大小来分配内存的,并不是完全按照程序申请的内存大小来进行分配 。
比如程序申请一个20字节的内存,内存分配器会分配一个32字节的内存空间 , 这么做是为了减少分配次数 。redis会申请不同大小的内存空间来存储不同业务不同类型的数据 , 由于内存按照固定大小分配且会比实际申请的内存要大一些,这个过程中会产生内存碎片 。
举个生活中的例子 , 帮助大家理解:
假设你正在整理一间图书馆 。图书馆的书架就像是Redis储存数据的内存空间 。每本书都代表不同大小的数据 。刚开始时,你把所有的书都按照大小放好 。小书在一侧,大书在另一侧 。这样你可以有效地利用书架的空间,也方便找书 。
但是 , 如果你需要移除一些书(删除某些数据),然后又加入新的书(新增数据),就可能出现问题了 。例如,你移除了一些大书,把它们的位置空出来,然后把新的小书放进去 。这样下来,原本属于大书的空间,现在只被小书部分占用,剩余的空白就成了“内存碎片” 。
又或者你有一堆新的大书要放,但书架上只有分散的小书的空位,无法容纳这些大书 。这个时候你可能需要重新排列整个书架(类似于Redis的内存整理)去腾出连续的大片空间来摆放这些新的大书 。
总结来说:当数据不断删除和新增时,内存中空出的位置可能无法完全匹配新数据的大?。?贾虏??幢焕?玫?ldquo;碎片”空间,这就是内存碎片 。
内存分配器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
推荐阅读
- Redis中的三种特殊类型
- Redis中的Big Key问题:排查与解决思路
- 离职“必删清单”:释放内存,轻装上阵,开启新篇章!这些事情你需要马上做!
- 在SpringBoot中通过Canal实现MySQL与Redis的数据同步
- MySQL如何与Redis保持数据一致性?
- 学透 Redis HyperLogLog,看这篇就够了
- 一文读懂 Redis 缓存系统
- 手撕 Golang 高性能内存缓存库 bigcache!
- Redis Stream 数据结构实现原理真的很强
- Go语言开发者的Apache Arrow使用指南:内存管理