Redis删除了大量数据后,为什么内存占用还是很高?

news/2023/6/9 19:14:13

前言

上周刚来了个应届小师弟,组长说让我带着,周二问了我这样一个问题:师兄啊,我用top命令看了下服务器的内存占用情况,发现Redis内存占用严重,于是我就删除了大部分不用的keys,为什么内存占用还是很严重,并没有释放呢?

嗯?为什么呢?今天就带着这个问题来介绍一下如何正确释放Redis的内存。

什么是内存碎片?

内存碎片这个概念应该不是第一听说了,熟悉JVM或者操作系统的应该都熟悉,以火车卖票为例,一个车厢128个车位,由于高峰期,只剩余两个位置了,但是此时三个人想要坐在一起,能够吹吹牛批,喝喝酒的,那么这三个人肯定不会买这节车厢的两个位置了,此时这两个位置可以称之为座位碎片

Redis专栏文章点击前往

操作系统中对于内存分配也是一样的,比如应用需要申请一块连续N个字节的空间,虽然剩余内存总量大于N个字节,但是没有一块连续的内存空间是N个字节,那么剩余的空间就是内存碎片。如下图:

上图中的空闲3个字节空闲2个字节都是内存碎片。

那么什么原因会造成内存碎片呢?这个其实大致分为两个原因,一个是操作系统的内存分配策略,一个是Redis自身原因,下面就这两个原因详细分析。

内存分配器的分配策略

内存分配器的分配策略一般是按照固定大小来分配内存,而不是按照应用程序申请的内存空间按需分配。比如8字节、16字节、32字节......

Redis提供了多种的内存分配策略,比如libcjemalloctcmalloc,默认使用jemalloc

jemalloc这种分配策略,是按照固定的空间分配,比如8字节、32字节....2KB、4KB等。当应用程序申请的内存接近某个固定值的时候,jemalloc则会分配固定的大小。比如申请了6字节,则会分配8字节的空间。

这种分配的方式的好处很明显,则会减少内存分配的次数,比如申请了20字节的内存,实际分配的是32字节的内存空间,当应用再写入10字节的数据时,则不会再次分配,剩余的12字节足够用了。这样就避免了一次的内存分配。如下图:

但是坏处也很明显,申请的和分配的空间不一样,则剩余的空间很可能形成内存碎片,一旦内存碎片多了,内存利用率也会随之降低,这是很可怕的。

Redis自身的原因

Redis作为键值对存储的数据库,本身键值对的大小就是不确定的,正如上面的例子中,Redis申请了20字节的空间,但实际分配却是32字节,那么剩余的12字节则会被闲置成为内存碎片。如下图:

上图中剩余12个字节空间则是闲置的,很有可能成为内存碎片,因此键值对大小不同则会造成一定的内存碎片,这是第一个原因。

第二个原因其实理解起来很简单,键值对的修改或者删除肯定会造成空间的扩容或者释放;

一方面,如果修改后的键值对变大或者变小了,势必会将占用的空间扩大或者释放不用的空间,如下图:

上图中键值对修改后变小了,从原来的10个字节变成了7个字节,从而释放了3个字节,此时剩余了5个字节的空闲空间。

另一方面,如果键值对删除了,则会释放掉占用的空间,形成空闲空间。

如何判断存在内存碎片?

这个对于运维人员来说很重要,一旦出现Redis运行缓慢或者阻塞了,一定需要先判断内存的占用情况,而不是说胡乱的重启Redis。

Redis自身提供了INFO命令,可以用来查询内存的使用情况,命令如下:


INFO memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1997159792
used_memory_rss_human:1.86G
…
mem_fragmentation_ratio:1.86
复制代码

上面的各种属性含义如下:

mem_fragmentation_ratio这个指标很清楚的展示了当前内存的碎片率,比如Redis申请了1000字节,但是操作系统实际分配的内存1800个字节,则mem_fragmentation_ratio=1800/1000=1.8

从上文也知道了,由于内存分配器的局限性,实际分配的内存绝大部分都是大于实际申请的内存,则如何通过mem_fragmentation_ratio这个值来衡量呢?这个值的范围在多少是正常的呢?

作者这里参照了许多开发人员的建议,列出了以下经验阀值:

  1. >1&&<1.5:在这个范围内是合理的,毕竟大部分情况下操作系统分配的内存总是总是大于实际申请的空间。
  2. >1.5:这表明内存碎片率已经超过50%,此时需要采取一些措施来降低碎片率了。
  3. <1:what?表明实际分配的内存小于申请的内存了,很显然内存不足了,这样会导致部分数据写入到Swap中,之后Redis访问Swap中的数据时,延迟会变大,性能会降低。

如何清理内存碎片?

既然存在内存碎片,那么的一定有方法清除内存碎片,最简单的方法则是重启Redis

但是这也存在一些风险,如下;

  1. 如果Redis未持久化,则数据会丢失(忽略从后端恢复)
  2. 即使持久化了,但是恢复数据时长不定,这个要根据AOF和RDB文件大小决定,在恢复阶段则无法提供服务。

好在Redis 4.0-RC3版本之后,Redis自身提供了一种清除内存碎片的方法

清除的原理很简单,通过复制拷贝将不连续的存放的数据搬到一起形成一块连续的内存空间,如下图:

如上图,清除之前AB不是连续的,中间隔着两个字节空闲1,但是在执行清除内存碎片操作之后,Redis拷贝了B空闲1,释放掉之前B的空间,此时空闲1空闲2则变成了连续的空闲空间了。

那么问题来了,这种方式固然好,但是对于单线程的Redis来说,通过这种拷贝复制的方式显然是一种耗时的操作,性能大大降低,那么有什么好的方法呢?

Redis提供了参数配置,可以控制清除内存碎片的时机,命令如下:

config set activedefrag yes
复制代码

以上命令启动自动清理,但是具体什么时候清理,还要受以下两个参数的影响:

  1. active-defrag-ignore-bytes 400mb:如果内存碎片达到了400mb,开始清理(自定义)
  2. active-defrag-threshold-lower 20:内存碎片空间占操作系统分配给 Redis 的总空间比例达到20%时,开始清理(自定义)

以上两个参数只有全部满足才会开始清理

除了以上触发清理内存碎片的参数,Redis还提供了两个参数来保证在清理过程中不影响处理正常的请求,如下:

  1. active-defrag-cycle-min 25:表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展
  2. active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。

以上两个参数控制了清理过程中的CPU时间占比,保证了正常处理请求不受影响

总结

本文以师弟的一个疑问开头介绍了删除数据导致内存占用还是很高的原因是存在内存碎片,导致内存碎片大致分为两个原因,如下:

  1. 内存分配策略局限性,一般都会分配固定的空间大小,导致实际分配的内存空间大于实际申请的,从而多出了许多不连续的空闲内存块。
  2. 键值对的修改、删除导致了内存的扩容或者释放,导致多余的不连续的空闲内存块。

介绍了如何通过INFO memory命令查看内存的碎片率,通过mem_fragmentation_ratio的经验阀值来判断异常。

介绍了Redis清理内存碎片的方式以、自动清理的两个触发条件、保证正常处理请求的两个控制CPU时间的参数。

作者:码猿技术专栏
链接:https://juejin.cn/post/6903318022887637005
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-4556055.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

即时通讯开发之TCP 交互数据流、成块数据流

目前建立在 TCP 协议上的网络协议特别多,有 telnet,ssh,有 ftp,有 http 等等。 这些协议又可以根据数据吞吐量来大致分成两大类: 交互数据类型&#xff1a;例如 telnet,ssh,这种类型的协议在大多数情况下只是做小流量的数据交换,比如说按一下键盘,回显一些文 字等等。 数据…

抠图总结

抠图总结 抠图&#xff1a;魔棒工具&#xff1a;适用于背景色单纯&#xff0c;物体边界清晰的图像。适量调节容差。多边形套索工具&#xff1a;适用于背景色复杂&#xff0c;物体边界不够清晰的图像。钢笔工具&#xff1a;使用与物体边界有长弧线的图像。快速选择工具&#xff…

java -- 14 多态、内部类、常用API

自动类型转换&#xff1a;多态下引用数据类型的类型转换强制类型转换案例&#xff1a;定义usb接口&#xff1a;定义鼠标和键盘的usb实现类&#xff0c;并有自己特有的方法&#xff0c;重写usb接口的方法&#xff0c;里面穿插了多态创建电脑类&#xff0c;把usb接口揉和进去&…

Photoshop透明婚纱照抠图处理

透明婚纱照抠图处理教程&#xff1a;先需要用钢笔等工具把人物部分抠出来包括婚纱部分。然后把抠出的人物图层复制一层&#xff0c;在通道选区婚纱部分较为清晰的通道并调出选区&#xff0c;回到图层面板后把选区反选按删除高光部分以外的图像&#xff0c;得到的图像就是我们抠…

婚纱抠图

婚纱抠图 原图&#xff1a;抠透明物体&#xff1a;如婚纱&#xff1b;在通道中&#xff0c;黑色表示没有。选一个边界清晰的通道&#xff0c;复制。在色阶中&#xff0c;调节&#xff0c;加大对比度。然后用多边形套索工具或是钢笔工具&#xff0c;用来抠图。使用钢笔工具&…

试纸云检测项目-前端用微信小程序扫描试纸,后端用图像识别的神经网络算法进行判断

有幸承接了一家医疗设备工厂的试纸云检测项目&#xff0c;原理是就是将前端扫描的试纸色块上传到服务器&#xff0c;然后在服务器进行一个算法判断&#xff0c;并且归类。这个项目的难点不再小程序的前端而是在服务器上的那套对于色块的颜色识别上。 onClick: function () {wx.…

java基础热门侠客养成_侠客养成手册点苍任务怎么做 点苍派任务详细攻略

在侠客养成手册的江湖中&#xff0c;遍布着许许多多的武林门派&#xff0c;在这些门派中也有着不少的任务可做。本文小编要为大家介绍的便是侠客养成手册点苍任务的攻略了&#xff0c;赶紧来了解下吧。从大理城通过传送点前往点苍派。向左进大殿和苍山上人对话完成任务&#xf…

微信支付点金计划—支付完成后自定跳转页面

最近遇到一件比较糟心事&#xff0c;给客户上线快两年的微信在线商城&#xff0c;最近决定升级&#xff0c;结果到支付完成后点击完成按钮无法直接返回商家...我检查了自己传的参数&#xff0c;发现并无问题&#xff0c;老版本是可以跳转的&#xff0c;当时很是懵逼&#xff0c…