前言

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

嗯?为什么呢?今天就带着这个问题来介绍一下如何正确释放Redis的内存。点击前往原文​mp.weixin.qq.com

什么是内存碎片?

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

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

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

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

内存分配器的分配策略

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

Redis提供了多种的内存分配策略,比如libc、jemalloc、tcmalloc,默认使用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.5:在这个范围内是合理的,毕竟大部分情况下操作系统分配的内存总是总是大于实际申请的空间。

>1.5:这表明内存碎片率已经超过50%,此时需要采取一些措施来降低碎片率了。

<1:what?表明实际分配的内存小于申请的内存了,很显然内存不足了,这样会导致部分数据写入到Swap中,之后Redis访问Swap中的数据时,延迟会变大,性能会降低。

如何清理内存碎片?

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

但是这也存在一些风险,如下;如果Redis未持久化,则数据会丢失(忽略从后端恢复)

即使持久化了,但是恢复数据时长不定,这个要根据AOF和RDB文件大小决定,在恢复阶段则无法提供服务。

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

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

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

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

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

config set activedefrag yes

以上命令启动自动清理,但是具体什么时候清理,还要受以下两个参数的影响:active-defrag-ignore-bytes 400mb:如果内存碎片达到了400mb,开始清理(自定义)

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

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

除了以上触发清理内存碎片的参数,Redis还提供了两个参数来保证在清理过程中不影响处理正常的请求,如下:active-defrag-cycle-min 25:表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展

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

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

总结

本文以师弟的一个疑问开头介绍了删除数据导致内存占用还是很高的原因是存在内存碎片,导致内存碎片大致分为两个原因,如下:内存分配策略局限性,一般都会分配固定的空间大小,导致实际分配的内存空间大于实际申请的,从而多出了许多不连续的空闲内存块。

键值对的修改、删除导致了内存的扩容或者释放,导致多余的不连续的空闲内存块。

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

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

redis怎么不让存byte_Redis 删除数据后不能自动释放内存么?相关推荐

  1. 删除数据后如何及时释放存储空间

    当表空间大小受限时,即便通过delete带条件删除部分数据,被删除数据所使用的空间,依然不会被释放.此时想要再添加新的数据可能会得到"磁盘空间不足"的报错. 一.创建实验场景步骤如 ...

  2. 达梦数据库删除数据后如何及时释放存储空间?

    当表空间大小受限时,即便通过delete带条件删除部分数据,被删除数据所使用的空间,依然不会被释放.此时想要再添加新的数据可能会得到"磁盘空间不足"的报错. 一.创建实验场景(注: ...

  3. Oracle 删除数据后释放数据文件所占磁盘空间

    . . . . . 测试的时候向数据库中插入了大量的数据,测试完成后删除了测试用户以及其全部数据,但是数据文件却没有缩小.经查阅资料之后发现这是 Oracle "高水位"所致,那么 ...

  4. 删除数据后无法恢复的固态盘

    删除数据后无法恢复的固态盘 为什么固态盘(简称:固态盘(简称:SSD))的数据恢复成功率那么低?关键的问题点就在它和机械硬盘完全不同的数据存储方式. 固态盘(简称:固态盘(简称:SSD))用闪存作为存 ...

  5. mysql删除数据后id自增不连续的解决方法

    mysql删除数据后id自增不连续的解决方法 参考文章: (1)mysql删除数据后id自增不连续的解决方法 (2)https://www.cnblogs.com/weifeng-888/p/1163 ...

  6. oracle修改删除数据,[Oracle 错误修改删除数据后的恢复方法

    [Oracle ERP维护人员必备] 错误修改删除数据后的恢复方法 Oracle ERP维护人员工作再小心也难免会有在正式库中误删或者误改数据并且已经commit的情况发生,那么我就要用到 - Ora ...

  7. java删除页面数据不刷新_Ajax请求数据与删除数据后刷新页面

    1.ajax异步请求数据后填入模态框 请求数据的按钮(HTML) ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS) //查询单个 functionquery(id) { ...

  8. Ajax请求数据与删除数据后刷新页面

    1.ajax异步请求数据后填入模态框 请求数据的按钮(HTML) <a class="queryA" href="javascript:void(0)" ...

  9. mysql 空位补0_MySQL 删除数据后物理空间未释放

    MySQL 删除数据后物理空间未释放 1. 进入数据库目录: cd  /var/lib/mysql/ 2. 备份要保存的数据库文件(切记!必须备份!部分数据库文件需要恢复!) mysqldump -h ...

最新文章

  1. 假装不知道有尽头(博弈论的诡计)
  2. 计算机房电磁辐射防护,计算机房电磁屏蔽
  3. vue不是内部或外部命令
  4. LazyInitializationException的四种解决方案–第2部分
  5. 论文浅尝 | 图神经网络的对抗攻击和防御相关文献集
  6. 递推(hdu2563)
  7. 自主巡航——高精度地图制作
  8. 百度深度学习图像识别决赛代码分享(OCR)
  9. cad画直角命令_给CAD图形进行倒直角的方法步骤
  10. 堪萨斯州立大学 计算机科学,美国堪萨斯州立大学排名怎么样?热门专业有哪些...
  11. linux启动服务日志,linux 服务启动日志
  12. linux洪水攻击路由器,(20)Linux下ICMP洪水攻击实例
  13. Halcon 图形窗口显示文本
  14. Java回炉之File
  15. 拓展kmp(2020新年第一篇博客 学无止境冲啊)
  16. Java第二课(多线程,jdbc,io)
  17. 打印服务经常自动关闭解决方法
  18. iOS真机播放MP4视频文件不出来的解决方法 AVPlayer
  19. HTML5 Plus 移动 App开发入门
  20. 白杨SEO:企业如何做微信营销推广?微信营销技巧有哪些?

热门文章

  1. Axure设计设备管理系统后台系统界面
  2. Flex手机开发系列一:新建Flex手机项目并打包
  3. oracle12c xtts迁移,记录一次XTTS迁移碰到的问题
  4. html背景只向x轴扩散,有趣的css—简单的下雨效果2.0版
  5. 怎么潜入别人家_小学生发明防雾口罩,别人家的孩子是怎么养成的?
  6. mysql都有哪些数据库日志_MySQL数据库之MySQL都有哪些日志?分别都代表什么
  7. 怎么在计算机修复flash,win10系统怎么用flash修复器?教你用flash修复器修复视频的方法...
  8. linux的qt5.5,Qt 5.5 正式发布,完全支持 Windows 10
  9. 怎么修改某一软件的服务器,怎样设置一个软件服务器地址
  10. android java资源包下载网站