败家玩意儿!Redis 竟然浪费了这么多内存!
作者|莱乌
作为内存数据库,内存空间大小对于 Redis 来说是至关重要的。内存越多,意味着存储的数据也会越多。但是不知道你有没有遇到过这样的情况,明明空间很大,但是内存的使用却不是很理想。
为什么会出现这样的情况呢?这期我们就来看看这个"诡异"的事件。
坐好了,准备发车!
- 思维导图 -
查看内存使用情况
首先想要知道 Redis 内存的使用情况,我们就需要获取相关的信息。
Redis 中查看内存相关信息是很简单的,只需要在命令行输入『info memory』就可以看到各种相关数据。在这里我罗列了一些较为重要的参数:
used_memory:已经使用了的内存大小。
used_memory_rss:redis 物理内存的大小。
mem_fragmentation_ratio:内存碎片率。
这里有一个内存碎片率的名词需要关注下,它可以用来表示当前的内存使用情况。
具体计算方式:
对于内存碎片率,一般保持在 1~1.5 之间是最合理的。
什么是内存碎片
了解了内存碎片率,那什么是内存碎片呢?
定义是这样的:由于一块连续空闲的空间比所要申请的空间小,导致这块空间不可用,对于内存整体来说就是内存碎片。
举个例子:
假设有一块 100MB 的连续空闲内存空间,你每次都会从中申请一块 30MB 的内存。那么当你申请了 3 次后,这块内存就只剩下了 10MB 的空间,第 4 次申请的时候就会失败。如果没有其它的空间释放并且每次申请的空间都比 10MB 大,那么剩下的空间对于整块内存来说就是内存碎片。
内存碎片导致的原因
Redis 中,最常用的是写入、修改、删除数据。这些操作在执行后都会产生 一定程度的内存碎片。
写入数据
Redis 中分配内存是根据固定的大小来划分内存空间的。为了减少分配次数,Redis 会根据申请的内存最接近的固定值分配相应大小的空间。
什么意思呢,假如 Redis 按照 8 字节、16 字节、32 字节、48 字节等来分配内存。当你想要存储一个 18 字节的数据时,此时 Redis 就会分配 32 字节(因为 32 是与 18 最接近的固定值)。如果这时候,再写入的数据需要的内存空间在 14 个字节内,那 Redis 就无需再进行分配了。
这就像你有不同的箱子,为了装东西,你需要找一个体积最接近的箱子来装。但是装进去后,你发现还有空间可以放一些小东西,就无需再找箱子了。
但是,这种分配空间的方式会带来一定程度的内存碎片。我们可以把固定大小的划分空间看成不同体积的箱子,每种箱子里的空间不同程度上都会有剩余。这些剩余的空间就是内存碎片。
修改数据
键值对进行修改时,可能会变大也会变小,相应的就会占用额外空间或者释放不用的空间。
如图中所示,当前 A、B、C 分别占用了 3、2、4 个字节,将 A 从 3 字节修改为 2 字节时,此时就会有 1 个字节的空间空了出来,这时就会出现 1 个字节的碎片。
那如果我将数据 A 从 3 字节修改为 4 字节呢?此时为了保持数据 A 的空间连续性,操作系统会把 B 拷贝到别的空间。此时又会出现 1 个字节的碎片。
删除数据
理解了修改数据,删除数据就很容易明白了。还是上边的例子,此时删除了数据 B,那么就释放了 2 个字节的空间。这样对于整个内存空间来说就产生了 2 个字节的碎片。
如何解决内存碎片
你可能会有疑问,内存碎片会有什么危害呢?
我们还是以上边的箱子来表示。你想想,如果你要把这些箱子都装上车运走,每个箱子里都有空出来的空间(内存碎片),那么运行一次的效率及性价比是不是会很低。同样,在 Redis 中,由于大量的碎片存在,会导致实际利用率变低。
那么我们有没有办法来解决内存碎片呢?
推倒重来
第一种方式很简单,直接推倒重来。也就是把 Redis 直接重启完事儿,内存一断电全世界就清净。但是这种暴力省事的方式却有很多隐患。
生产环境中你这么搞的话得提前烧烧香,保佑不会出什么问题。如果你没进行过持久化,那么就别烧了,烧了也没用。如果有持久化的话,那么恢复时长还得取决你持久化文件的大小,在这个阶段还无法提供服务。糟心不?
空间置换
那么有没有不这么刺激的方式。
有的,高版本的 Redis 提供了内存碎片清理的方式。一言以蔽之,就是空间置换。
怎么个置换法?我们的目的是为了消除内存碎片,那么我们把已使用的内存数据重新整理到一起不就行了吗?让不连续的空间变成连续的,剩下的空间,继续来分配。
画个图理解下:
但是,说说还是挺容易的,理论到实践中间还隔着性能损耗。
在进行多次数据拷贝过程中,单线程的 Redis 只能干等着,无法响应客户端的请求。这时候只能干瞪眼,性能太受影响。
凉,那该咋整?!别急,有缓解的策略,你接着往下看。
Redis 中有专门的参数设置用来进行自动清理内存碎片:activedefrag yes。
这个命令是启动清理功能的,这还不够,Redis 中还需要其他的条件限制才能够进行清理。
下面参数都是满足任一条件后就可以进行清理:
active-defrag-ignore-bytes 100mb:
碎片达到100MB时,开启清理。
active-defrag-threshold-lower 10:
当碎片超过 10% 时,开启清理。
active-defrag-threshold-upper 100:
内存碎片超过 100%,尽最大清理。
在处理的过程中,为了避免对正常请求的影响,同时又能保证性能。Redis 同时还提供了监控 CPU 占用比例的参数,在满足以下条件时才会保证清理正常开展:
active-defrag-cycle-min 5:
清理内存碎片占用 CPU 时间的比例不低于此值,保证清理能正常开展。
active-defrag-cycle-max 75:
清理内存碎片占用 CPU 时间的比例不高于此值。一旦超过则停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致其它请求延迟。
总结
查看内存使用情况
在命令行执行 info memory 即可查看 Redis 内存相关信息。根据内存碎片率可以在一定时机内进行清理碎片清理。
内存碎片导致原因
写入数据时,Redis 为了减少分配次数在分配内存是根据固定的大小来划分内存空间的。修改数据时会释放或占用额外的内存空间,删除数据时会释放空间。这样就会产生不同程度的内存碎片。
如何解决内存碎片
通过重启 Redis 的方式进行处理,如果没有持久化可能会导致事故。在持久化情况下,恢复速度需要取决于文件的大小。
通过空间置换方式,也就是将已使用的内存数据重新整理到一起。
特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:
长按订阅更多精彩▼如有收获,点个在看,诚挚感谢
败家玩意儿!Redis 竟然浪费了这么多内存!相关推荐
- [原创]Redis BUG系列(I)——SDS字符串的sdssplitlen函数实现顺序BUG,浪费了计算与内存资源
这里写自定义目录标题 简要 BUG介绍 源码与说明 BUG内容 修改方法 BUG验证 BUG影响 版本范围 哪些时候调用sdssplitlen这个函数? 我在GIT上提交的pull request 简 ...
- Redis 过期键删除策略、内存淘汰机制
文章目录 过期键删除策略 定时删除 惰性删除 定期删除 Redis的选择 内存淘汰机制 redis中缓存的数据是有过期时间的,当缓存数据失效时,redis会删除过期数据以节省内存,那redis是怎样怎 ...
- 高性能分布式缓存redis(持久化原理 安全策略 过期删除内存淘汰策略 性能压测 高可用 Redis Cluster)
redis redis(持久化原理 安全策略 过期删除&内存淘汰策略 性能压测 高可用 Redis Cluster) 1. 持久化原理 1.1 持久化流程(落盘) 1.2 RDB详解 1.2. ...
- redis value多大会影响性能_选择合适Redis数据结构,减少80%的内存占用
前言 redis作为目前最流行的nosql缓存数据库,凭借其优异的性能.丰富的数据结构已成为大部分场景下首选的缓存工具. 由于redis是一个纯内存的数据库,在存放大量数据时,内存的占用将会非常可观. ...
- redis mysql windows_Redis+Mysql模式和内存+硬盘模式的异同
学习任何新知识,都是一个循序渐进的过程,从刚开始的懵懂无知,到简单熟悉,然后突然的彻悟,成果让人欣喜若狂,心情也会快乐很久. redis+mysql和内存+硬盘类似的地方 首先看图: 首先,我们知道, ...
- redis 删除数据,但是占用内存没有下降原因及解决办法
在使用 Redis 时,我们经常会遇到这样一个问题:明明做了数据删除,数据量已经不大了,为什么使用 top 命令查看时,还会发现 Redis 占用了很多内存呢? 实际上,这是因为,当数据删除后,Red ...
- 如何使用Redis Data Reveal(rdr)查看redis中每个key占用的内存大小
如何使用Redis Data Reveal(rdr)查看redis中每个key占用的内存大小 一.为什么要查看redis中每个key的占用 二.怎么查看redis中每个key的占用 一.为什么要查看r ...
- 这款刷爆抖音的玩意儿,竟然是程序员的福音!
当代80.90后的颈椎多多少少都有点问题 毕竟我们是被称做低头族的一代 虽然大家呼吁我们放下手机多出去走走 看看周围的风景 我们也曾经尝试过放下过手机 但是最后发现还是手机最好玩 当我们这一代成为了上 ...
- 利用TCMalloc替换Nginx和Redis默认glibc库的malloc内存分配
TCMalloc的全称为Thread-Caching Malloc,是谷歌开发的开源工具google-perftools中的一个成员.与标准的glibc库的Malloc相比,TCMalloc库在内存分 ...
最新文章
- 数据结构与算法:15 树
- sqlite 实例教程 IOS下用sqlite打造词典
- java工程前面有个红色感叹号
- ASP.NET Core官方计划路线及需要废除的一些Framework技术
- 今日头条野心背后逃不过的10个问题
- python2.7 跨文件全局变量的方法
- 上传书籍进度信息到服务器...,使用HttpWebRequest实现大文件上传资料.pdf
- 安卓真机如何连接本地服务器_一分钟搭建可供手机访问的本地服务器 (安卓,ios手机通用)...
- python队列怎么用_如何在Python中使用多处理队列? - python
- Spring Data JPA 从入门到精通~SpEL表达式的支持
- 如何绘制逻辑图 — 5. 要素的属性:系统与模块
- 数据安全:英国公司泄露超过100万人的指纹和面部识别数据
- python 多进程 调用模块内函数_python--多进程的用法详解实例
- C# 中的readonly属性
- Typora如何设置图片的默认保存路径
- 值得推荐的C/C++开源框架和库
- HDU 2899 :(二分求最小值)
- atitit.元编程总结 o99
- 超级搜索术,提升解决问题的能力
- 分数乘法计算机题,分数乘法计算题100道测试卷(无答案)
热门文章
- AttributeError: ‘Tensor‘ object has no attribute ‘encoder‘
- poj1716(差分约束+SPFA)
- 思维dp ---- CF41D Pawn [可达状态统计dp]
- luogu P3393 逃离僵尸岛(点权最短路 + 多源BFS)
- 非二叉树 UVA297 四分树 Quadtrees
- python并发1000个http请求_php下api接口的并发http请求
- from name as id为啥报错
- c++ 调用labview_LabVIEW面向对象编程_初窥门径(5):开发方式漫谈
- 玻利维亚java_BlogJava
- vue cli根据不同的环境打包