Redis 删除数据后,为什么内存占用率还是很高?
在使用 Redis 时,我们经常会遇到这样一个问题:明明做了数据删除,数据量已经不大了,为什么使用 top 命令查看时,还会发现 Redis 占用了很多内存呢?
实际上,这是因为,当数据删除后,Redis 释放的内存空间会由内存分配器管理,并不会立即返回给操作系统。所以,操作系统仍然会记录着给 Redis 分配了大量内存。
但是,这往往会伴随一个潜在的风险点:Redis 释放的内存空间可能并不是连续的,那么,这些不连续的内存空间很有可能处于一种闲置的状态。这就会导致一个问题:虽然有空闲空间,Redis 却无法用来保存数据,不仅会减少 Redis 能够实际保存的数据量,还会降低 Redis 运行机器的成本回报率。
所以,这节课,我就和你聊聊 Redis 的内存空间存储效率问题,探索一下,为什么数据已经删除了,但内存却闲置着没有用,以及相应的解决方案。什么是内存碎片?
什么是内存碎片?
通常情况下,内存空间闲置,往往是因为操作系统发生了较为严重的内存碎片。那么,什么是内存碎片呢?
为了方便你理解,我还是借助高铁的车厢座位来进行解释。假设一个车厢的座位总共有 60 个,现在已经卖了 57 张票,你和 2 个小伙伴要乘坐高铁出门旅行,刚好需要三张票。不过,你们想要坐在一起,这样可以在路上聊天。但是,在选座位时,你们却发现,已经买不到连续的座位了。于是,你们只好换了一趟车。这样一来,你们需要改变出行时间,而且这趟车就空置了三个座位。
其实,这趟车的空座位是和你们的人数相匹配的,只是这些空座位是分散的,如下图所示:
我们可以把这些分散的空座位叫作“车厢座位碎片”,知道了这一点,操作系统的内存碎片就很容易理解了。虽然操作系统的剩余内存空间总量足够,但是,应用申请的是一块连续地址空间的 N 字节,但在剩余的内存空间中,没有大小为 N 字节的连续空间了,那么,这些剩余空间就是内存碎片(比如上图中的“空闲 2 字节”和“空闲 1 字节”,就是这样的碎片)。
那么,Redis 中的内存碎片是什么原因导致的呢?接下来,我带你来具体看一看。我们只有了解了内存碎片的成因,才能对症下药,把 Redis 占用的内存空间充分利用起来,增加存储的数据量。
内存碎片是如何形成的?
其实,内存碎片的形成有内因和外因两个层面的原因。简单来说,内因是操作系统的内存分配机制,外因是 Redis 的负载特征。
内因:内存分配器的分配策略
内存分配器的分配策略就决定了操作系统无法做到“按需分配”。这是因为,内存分配器一般是按固定大小来分配内存,而不是完全按照应用程序申请的内存空间大小给程序分配。
Redis 可以使用 libc、jemalloc、tcmalloc 多种内存分配器来分配内存,默认使用 jemalloc。接下来,我就以 jemalloc 为例,来具体解释一下。其他分配器也存在类似的问题。
jemalloc 的分配策略之一,是按照一系列固定的大小划分内存空间,例如 8 字节、16 字节、32 字节、48 字节,…, 2KB、4KB、8KB 等。当程序申请的内存最接近某个固定值时,jemalloc 会给它分配相应大小的空间。
这样的分配方式本身是为了减少分配次数。例如,Redis 申请一个 20 字节的空间保存数据,jemalloc 就会分配 32 字节,此时,如果应用还要写入 10 字节的数据,Redis 就不用再向操作系统申请空间了,因为刚才分配的 32 字节已经够用了,这就避免了一次分配操作。
但是,如果 Redis 每次向分配器申请的内存空间大小不一样,这种分配方式就会有形成碎片的风险,而这正好来源于 Redis 的外因了。
比如说,应用 A 保存 6 字节数据,jemalloc 按分配策略分配 8 字节。如果应用 A 不再保存新数据,那么,这里多出来的 2 字节空间就是内存碎片了,如下图所示:
第二个外因是,这些键值对会被修改和删除,这会导致空间的扩容和释放。具体来说,一方面,如果修改后的键值对变大或变小了,就需要占用额外的空间或者释放不用的空间。另一方面,删除的键值对就不再需要内存空间了,此时,就会把空间释放出来,形成空闲空间。
相关文章
- 浅谈redis内存数据的持久化方式
- Redis主从模式实现热备:极致数据可靠性的保障。(redis主从热备)
- Redis系统压力测试:改善性能的最佳方案(redis压测)
- 使用 Redis 操作指定数据库(redis指定数据库)
- Redis中实现的复制数据的绝佳方案(redis复制数据)
- 深度解析:Redis服务器的本质和作用(redis服务器是什么)
- 库Redis实现数据库更新的简易方法(redis 如何更新数据)
- 一键式批量往Redis写入数据(批量往redis写入数据)
- 学习Redis攻克挑战,拥抱成功(怎么学好redis)
- 让Redis订阅关系凸显构建设计(订阅关系redis设计)
- 时间监控Redis实时跟踪Key过期时间(监听redis 过期)
- 游戏世界Redis 引领数据之风(游戏数据 redis)
- 系统使用Redis之所以被缓存系统使用一次性解决多头问题(为什么redis被缓存)
- 基于Redis的下拉框数据存储实现(下拉框数据 redis)
- 如何简易创建Redis集群(创建redis集群命令)
- 如何快捷导出Redis中的数据(如何导出redis的数据)
- 优化Redis开启多线程存取数据(多线程redis存数据)
- 商业领域中借助Redis开启性能突破之路(商用redis)
- 如何熟练使用Redis一个实战案例演示(redis项目实战案例)
- Redis集群模式大数据统计分析之路(redis集群模式统计)
- 持久化Redis集群实现可靠的内存持久化(redis集群方案 内存)
- 利用Redis实现多数据结构存储(redis集合的数据结构)
- 如何利用Redis限制消费速度(redis限制消费速度)
- Redis连接优化之重连机制(redis链接优化重连)
- 零售店的故事Redis的Zero返回(redis 返回0)
- Redis计数建立同步数据的持久化(redis 计数与同步)
- 从Redis运行逻辑看数据存储技术(redis运行逻辑)
- Redis查询第十个数据的实践经验(redis查询第十个数据)