.net redis定时_一场由fork引发的超时,让我们重新探讨Redis的抖动问题

​​​​​​​​​​​​​​​​​​​​​​​​​​​​摘要:一次由fork引发的时延抖动问题。

背景介绍

华为云数据库GaussDB(for Redis) 是一款基于计算存储分离架构,兼容Redis生态的云原生NoSQL数据库;它依靠共享存储池实现了强一致,支持持久化落盘存储,保证数据的安全可靠。其核心特点是:存算分离、强一致、低成本、超大容量。

GaussDB(forRedis)服务团队在支撑某客户业务上云的过程中,发现一次由fork引发的时延抖动问题,本着对客户负责任的态度,我们详细探究了fork这个系统调用的性能影响,并且在最新的GaussDB(for Redis)版本已解决了这个抖动问题,清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。

问题焦点

1)华为云GaussDB(for Redis) 服务在某客户上云线调测过程中发现,系统上量后规律性的出现每5分钟1次的时延抖动问题。

2)华为云GaussDB(for Redis)团队经过攻关,最终确认抖动原因是fork导致并解决了这个问题。而fork是开源Redis的一个重要依赖,希望通过本文的分享,能够帮助大家在使用开源Redis的时候,充分认识fork的影响,从而选择更优的方案。

问题现象

某客户业务接入GaussDB(for Redis)压测发现,每5分钟系统出现一次规律性的时延抖动:

1)正常情况消息时延在1-3ms,抖动时刻时延达到300ms左右。

2)通常是压测一段时间后开始出现抖动;抖动一旦出现后就非常规律的保持在每5分钟1次;每次抖动的持续时长在10ms以内。

下图是从系统慢日志中捕获到的发生抖动的消息样例(对敏感信息进行了遮掩):

15754df1d0762310edb0f768e2616ba9.png

问题分析

1. 排查抖动源:

1)由于故障的时间分布非常规律,首先排除定时任务的影响,主要包括:

l agent:和管控对接的周期性统计信息上报任务

l 内核:执行引擎(Redis协议解析)和存储引擎(rocksdb)的周期性操作(包括rocskdb统计,wal清理等)

屏蔽上述2类定时任务后,抖动依然存在。

2)排除法未果后,决定回到正向定位的路上来。通过对数据访问路径增加分段耗时统计,最终发现抖动时刻内存操作(包括allocate、memcpy等)的耗时显著变长;基本上长出来的时延,都是阻塞在了内存操作上。(截图为相关日志,单位是微秒)

3)既然定位到是系统级操作的抖动,那么下一步的思路就是捕获抖动时刻系统是否有异常。我们采取的方法是,通过脚本定时抓取top信息,分析系统变化。运气比较好,脚本部署后一下就抓到了一个关键信息:每次在抖动的时刻,系统中会出现一个frm-timer进程;该进程为GaussDB(for Redis)进程的子进程,且为瞬时进程,持续1-2s后退出。

f793070ba80aaf1791e79a80d541c787.png
d2c4659b0534524a5a6058fb4eb5296a.png

4)为了确认该进程的影响,我们又抓取了perf信息,发现在该进程出现时刻,Kmalloc, memset_sse,memcopy_sse等内核系统调用增多。从上述信息推断,frm-timer进程应该是被fork出来的,抖动源基本可锁定在fork frm-timer这个动作上。

2.确定引发抖动的代码:

1)分析frm-timer的来历是下一步的关键。因为这个标识符不在我们的代码中,所以就需要拉通给我们提供类库的兄弟部门联合分析了。经过大家联合排查,确认frm-timer是日志库liblog中的一个定时器处理线程。如果这个线程fork了一个匿名的子进程,就会复用父进程的线程名,表现为Redis进程创建出1个名为frm-timer的子进程的现象。

2)由于frm-timer负责处理liblog中所有模块的定时器任务,究竟是哪个模块触发了上述fork?这里我们采取了一个比较巧妙的方法,我们在定时器处理逻辑中增加了一段代码:如果处理耗时超过30ms,则调用std:: abort()退出,以生成core栈。

3)通过分析core栈,并结合代码排查,最终确认引发抖动的代码如下:

5f69555f1ce18b91f55d888510709c1e.png

上述代码是用来周期性归档日志的,它每5分钟会执行1次 system系统调用来运行相关脚本,完成归档日志的操作。而Linux system系统调用的源码如下,实际上是一个先fork子进程,再调用execl的过程。

c4c50de3891b7502792226f50f146119.png

4)分析至此,我们还需要回答最后一个问题:究竟是fork导致的抖动,还是脚本内容导致的抖动?为此,我们设计了一组测试用例:

l 用例1:将脚本内容改为最简单的echo操作

l 用例2:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行fork操作

l 用例3:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行先fork,再excel的操作

l 用例4:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行system的操作

l 用例5:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行先vfork,再excel的操作

最终的验证结果:

l 用例1:有抖动。

l 用例2:有抖动。

l 用例3:有抖动。

l 用例4:有抖动。

l 用例5:无抖动。

用例1结果表明抖动和脚本内容无关;用例2、3、4的结果表明调用system引发抖动的根因是因为其中执行了fork操作;用例5的结果进一步佐证了抖动的根因就是因为fork操作。最终的故障原因示意图如下:

2fc95059998fb94ebfc80015464db69b.png

3. 进一步探究fork的影响:

1)众所周知,fork是Linux(严格说是POSIX接口)创建子进程的系统调用,历史上看,主流观点大多对其赞誉有加;但近年间随着技术演进,也陆续出现了反对的声音:有人认为fork是上个时代遗留的产物,在现代操作系统中已经过时,有很多害处。激进的观点甚至认为它应该被彻底弃用。(参见附录1,2)

2)fork当前被诟病的主要问题之一是它的性能。大家对fork通常的理解是其采用copy-on-wirte写时复制策略,因此对其的性能影响不甚敏感。但实际上,虽然fork时可共享的数据内容不需要复制,但其相关的内核数据结构(包括页目录、页表、vm_area_struc等)的复制开销也是不容忽视的。附录1、2中的文章对fork开销有详细介绍,我们这回遇到的问题也是一个鲜活的案例:对于Redis这样的时延敏感型应用,1次fork就可能导致消息时延出现100倍的抖动,这对于应用来说无疑是不可接受的。

4.原生Redis的fork问题:

4.1 原生Redis同样被fork问题困扰(参见附录3,4,5),具体包括如下场景:

1)数据备份

备份时需要生成RDB文件,因此Redis需要触发一次fork。

2)主从同步

全量复制场景(包括初次复制或其他堆积严重的情况),主节点需要产生RDB文件来加速同步,同样需要触发fork。

3)AOF重写

当AOF文件较大,需要合并重写时,也会产生一次fork。

4.2 上述fork问题对原生Redis的影响如下:

1)业务抖动

原生Redis采用单线程架构,如果在电商大促、热点事件等业务高峰时发生上述fork,会导致Redis阻塞,进而对业务造成雪崩的影响。

2)内存利用率只有50%

Fork时子进程需要拷贝父进程的内存空间,虽然是COW,但也要预留足够空间以防不测,因此内存利用率只有50%,也使得成本高了一倍。

3)容量规模影响

为减小fork的影响,生产环境上原生Redis单个进程的最大内存量,通常控制在5G以内,导致原生Redis实例的容量大大受限,无法支撑海量数据。

解决方法

1.修改日志库liblog中的周期性归档逻辑,不再fork子进程。

2.系统排查并整改GaussDB(for Redis)代码(包括使用的类库代码)中的fork调用。

3.最终排查结果,实际只有本次的这个问题点涉及fork。当前修改后即可确保GaussDB(for Redis)的时延保持稳定,不再受fork性能影响。

注:GaussDB(for Redis)由华为云基于存算分离架构自主开发,因此不存在原生Redis的fork调用的场景。

总结

本文通过分析GaussDB(for Redis)的一次由fork引发的时延抖动问题,探究了fork这个系统调用的性能影响。最新的GaussDB(for Redis)版本已解决了这个抖动问题,并清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。希望通过这个问题的分析,能够带给大家一些启发,方便大家更好的选型。

附:

1.[是时候淘汰对操作系统的 fork() 调用了]

https://www.infoq.cn/article/BYGiWI-fxHTNvSohEUNW

2.[Linux fork那些隐藏的开销]

https://www.mdeditor.tw/pl/29L0

3.[Redis官方文档]

https://redis.io/topics/latency

4.[Redis的一些坑]

https://www.jianshu.com/p/03df6fd516eb

5.[Redis 常见问题之-fork操作]

https://blog.csdn.net/longgeqiaojie304/article/details/89407214

6.[GaussDB(for Redis)官网链接]

https://www.huaweicloud.com/product/gaussdbforredis.html

本文作者:华为云数据库GaussDB(for Redis)团队

点击关注,第一时间了解华为云新鲜技术~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中关于树的一些定义

树概念树树的叶子节点节点的度分支结点树的度树的高度树的深度二叉树二叉树的特点满二叉树完全二叉树二叉查找树示例代码实现开发环境运行结果概念 本文以一个简单的树为例,如下图,来记录树的一些概念。 树 一种由n个节点组成的具有一定层次关系的有…

02_Spring Cloud Alibaba整合通用Mapper+Lombok+Mysql

Spring CLoud 整合通用MapperLombokMysql 文章目录一、使用Spring Initializr快速创建Spring Boot应用二、相关依赖2.1. 添加依赖2.2. mybatis添加插件2.3. 在resources目录下面创建generator目录存放generatorConfig.xml2.3.1. config.properties配置文件2.3.2. lombok插件2.3…

如何快速深入理解监控知识? | 技术干货

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!作者:叶左左链接:https://www.jianshu.com/p/5d76d31b39580 监…

bootstrap 模态框无法使用_模态窗 Modal Window - 产品中的??注意力设计

本文是「经典交互模式」系列第二篇,前文回顾:面包屑导航 Breadcrumbs Trail全文目录什么是模态窗 模态窗的使用问题 模态框应用实践 什么是模态窗 Modal Window我们在各种不同的屏幕应用中见过「模态窗」,全屏幕模态窗、弹出信息框、&#xf…

QQmlApplicationEngine failed to load component qrc:/main.qml:-1 No such file or directory

记录qml运行时出现的问题问题描述解决办法问题描述 qml项目编译的时候通过,但是在运行时出现图中所示错误提示。 解决办法 在项目所在的文件夹下删除编译生成的目录,我的项目编译生成目录如下图: 删除编译生成的文件夹后,项目…

服务迁移之路 | Spring Cloud向Service Mesh转变 | 技术干货

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!作者: 李宁转自:博云技术社区Spring Cloud基于Spring Boot开发…

oracle使用关键字做表字段名_ArcGIS SQL使用

本主题将介绍 ArcGIS 中的选择表达式所用的常规查询的各个元素。ArcGIS 中的查询表达式使用常规 SQL 语法。警告:SQL 语法不适用于使用字段计算器计算字段。字段在 SQL 表达式中指定字段时,如果该字段名可能产生岐义(比如与 SQL 保留关键字相同)&#xf…

uml类图浅录

uml类图UML中类图的绘制单个类图的绘制类图中的成员访问属性UML类图中类与类的几种关系关联代码示例解释UML类图表示多重性说明依赖代码示例解释uml类图表示继承示例代码解释UML类图表示实现示例代码解释UML类图表示聚合示例代码UML类图表示组合示例代码解释UML类图表示绘制UML…

03_SpringCloud整合Ribbon实现负载均衡

采用随机负载均衡策略,四线服务之间的调用 2个用户中心,1个内容中心,内容中心调用用户中心服务 package com.itmuch.contentcenter.service.impl;import com.itmuch.contentcenter.dao.content.ShareMapper; import com.itmuch.contentcent…

容器精华问答 | 我们为什么需要容器?

戳蓝字“CSDN云计算”关注我们哦!容器技术是这两年热门的话题,因为容器技术给我们带来了很多方便的地方,节约了不少成本,不管是在运维还是开发上。今天,就让我们来看看关于容器更加有深度的问题吧。1Q:什么…

C++11继承构造函数在类中的使用

继承构造函数概念衍生问题使用示例注意扩展使用(函数)示例代码输出结果注意概念 继承构造函数在C11特性中随之提及,其大概可以理解为: 解决了派生类无法直接使用基类中的构造函数的这一问题。 正常情况下,基类定义了自…

grep从文件末尾开始找_新人自学前端到什么程度才能找工作?

这个问题打我记事起到现在,问过我的人,没有1000也有800了。足以见得这个问题是多么的不得人心。自学前端开发,不管他在网上百度了多少资料,看了多少教程,你总得先做个网页出来。所以,很多人都是从html标签开…

Spring Tool Suite 4安装Lombok

Lombok官网:https://www.projectlombok.org/download 文章目录一、下载jar包二、lombok.jar复制三、运行lombok.jar四、安装lombok4.1 点击确定4.2 找到SpringToolSuite4.exe五、以管理员运行Spring Tool Suite 4六、引入lombok依赖6.1 maven项目6.2 普通web项目七、…

base昆明,腾讯云在合作伙伴的阵营中@了TA

戳蓝字“CSDN云计算”关注我们哦!技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!在今年的腾讯“三合一”大会上,阿晶得到了这样一则数据:截至目…

IntelliJ IDEA 2019 安装lombok

文章目录一、安装插件二、添加lombok依赖三、重启IntelliJ IDEA四、效果图五、如果不生效一、安装插件 二、添加lombok依赖 <!--Lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version&g…

记录C++类中的一次函数调用

引用 之前遇到一次函数调用结果的问题&#xff0c;今天在这里做一下记录。 一个基类&#xff0c;一个派生类&#xff0c;两个类中都有一个函数名相同&#xff0c;参数相同&#xff0c;参数不同的函数&#xff0c;创建基类指针指向派生类对象&#xff0c;调用相应的函数&#x…

bootstrap table移动端_bootstrap介绍

简介bootstrap是一款前端开发自适应页面的js库&#xff0c;可以让你在开发网页的时候轻松实现网站的PC与移动端兼容&#xff0c;避免在移动端上面出现样式错位等。原理bootstrap的原理是媒体查询CSS3的media&#xff0c;用于检测屏幕&#xff0c;从而改变样式的百分比。结构boo…

Spring Tool Suite 4 自动提示功能

文章目录一、java文件 自动提示二、JavaScript文件 自动提示三、HTML文件 自动提示四、导出配置文件五、编辑导出的配置文件5.1 java提示规则替换5.2 html提示规则替换六、导入配置好的文件一、java文件 自动提示 打开STS→Windows→Preferences→Java→Editor→Content Assis…

中立安全、赋能产业,UCloud优刻得凭差异化路线进军产业互联

2019年5月28日&#xff0c; 国内领先的中立云计算服务商UCloud优刻得&#xff08;以下简称UCloud&#xff09;在北京召开以“中立安全、赋能产业”为主题的UCloud用户大会暨Think in Cloud北京大会。面对走向纵深的产业互联网&#xff0c;UCloud强调做“不和用户竞争的云”&…

Spring Tool Suite 4 添加反编译插件

文章目录一、进入商店市场二、查找插件&#xff0c;输入jad搜索三、点击安装四、接收协议、安装五、重启Spring Tool Suite 4六、效果图一、进入商店市场 二、查找插件&#xff0c;输入jad搜索 三、点击安装 四、接收协议、安装 五、重启Spring Tool Suite 4 六、效果图