记在Linux上定位后台服务偶发崩溃的问题
问题描述
在最近的后台服务中,新增将某个指令的请求数据落盘保存的功能。在具体实现时,采用成员变量来保存请求消息代理头,在接收响应以及消息管理类释放时进行销毁。测试反馈,该服务偶发崩溃。
问题分析
测试环境上运行的是rel版程序,由于在编译时去掉了调试信息(-g)以及开启O3级别优化,从崩溃dump的堆栈上,只看到程序崩溃的调用栈,函数入参等被优化掉,由于此处没有打日志,只能想其他办法来复现。猜测是重复释放指针导致的崩溃,接下来继续分析。
从rel版本的调用栈上看,只看见最后销毁的函数调用,而在实际代码中,有两处销毁的函数调用入口,为什么在dump中看到的调用栈顺序与实际代码不一致呢?猜测是开启O3优化,将函数内联。
做了以下实验来分析,
void test_dump()
{
int* p = NULL;
*p = 2; // occur dump
}
void test_f2(int b)
{
b += 1;
test_dump();
}
void test_f1(int a)
{
a+=1;
test_f2(a);
}
int main()
{
test_f1(1);
return 0;
}
在Debug以及Rel模式下,触发崩溃,使用gdb来输出堆栈信息分别如下:


结论:在Rel模式下,O3级别的优化内联了调用函数,如果从崩溃点往上回溯有多个可能入口点,那仅凭dump信息不能确认是哪个入口触发的崩溃。
构造测试环境
通过分析代码,得知要触发可能的多重释放,需要构造一边创建,一边销毁的场景。
- 创建:可通过测试工具,定时高频发送特定指令,触发创建流程
- 销毁:可在定时任务中,进行无效状态上报,触发销毁流程
为了加快崩溃复现速度,创建以及销毁的速度需要合理匹配,如果太快销毁,会导致无法进入创建流程。经过分析尝试,最终
设定测试工具每50毫秒发送一次,后台服务每50ms上报无效状态。
为进一步验证崩溃的想法,在销毁操作等关键路径添加日志,启动Rel版来重现。经过长时间的测试,获得了2次宝贵的崩溃dump以及对应的日志。每次dump要花费2个半小时甚至更多才能复现,说明这个问题是偶发问题,很可能与多线程竞态有关。复现该问题的时间成本有点高,不过,从获得的dump以及日志已足以定位问题。
日志分析
同一后台服务,不同业务模块的日志分布在不同日志文件中,在分析时,需要将各部分日志聚合起来,方便复现全流程。在聚合时,可以按需截取各模块的最后若干行日志,每种日志中包含正常以及异常的日志,将其汇总到单一文件,然后结合代码进行逐行关联分析。
在分析过程中,遇到一些框架方面的疑问,通过询问相关同事得到解答。目前的消息收发框架在接收消息时,先将消息放入线程池的消息队列,通过信号量来唤醒线程,线程从消息队列中获取消息,从消息中取出处理函数进行处理。
在应用层处理不同消息时,可能处理同一个变量时,会有发生竞态。通过对释放指针的分析,正常释放指针指都有一定的规律,当触发崩溃时,释放的指针值与正常的值有明显区别。
经验小结
- 发现有dump文件时,查看dump文件生成时间,将当时的日志以及可执行文件,连同dump文件一并放在独立的文件夹中,便于后续分析。因为当前的日志文件以及可执行文件可能被删除以及更新。
- 每一次问题的解决,都是一次对已有系统的再深入认识,理解。
- 构造复现环境时,要使用Rel版本,且只能通过日志来确认程序流程,而不是断点。
- 在linux上,不能使用嵌套属性的互斥锁,它会破坏设计意图,让潜在的死锁更加难以发现。让错误尽早暴露好过后续找错。
- 大胆假设,小心求证,胜利的曙光终会出现。
参考文章:
线上问题 不能gdb调试怎么处理
Linux 环境下多线程 C/C++ 程序的内存问题调试
记在Linux上定位后台服务偶发崩溃的问题的更多相关文章
- 在linux上部署tomcat服务
在linux上部署tomcat 1.安装JDK 2.下载tomcat http://tomcat.apache.org/download-70.cgi 3.上传到服务器,并解压 4.上传war包或者已 ...
- 关于Linux上的SSH服务无法启动,提示“/var/empty/sshd must be owned by root and not group or world-writable”错误
首先通过物理终端进入到linux上,手工检查ssh发现没运行# /etc/init.d/sshd statussshd is stopped 手动启动服务,发现报告权限错误.# /etc/init.d ...
- Linux上搭建SVN服务
环境:centos7 一.搭建svn服务 1. 安装svn yum -y install subversion 2. 创建一个目录作为svn服务的地址(svn://192.168.0.2:3690 访 ...
- 在Linux上安装Oracle服务的操作步骤
如题,将我在云服务器上安装Oracle服务的惨痛经历分享出来,期间查找的资料踩过的坑无数,希望对大家能有帮助 闲话少叙,直接开始 首先,由于服务器比较差,需要先设置swap 查看是否设置swap虚拟内 ...
- JAVAEE——宜立方商城07:Linux上搭建Solr服务、数据库导入索引库、搜索功能的实现
1. 学习计划 1.Solr服务搭建 2.Solrj使用测试 3.把数据库中的数据导入索引库 4.搜索功能的实现 2. Solr服务搭建 2.1. Solr的环境 Solr是java开发. 需要安装j ...
- 在Linux上安装Memcached服务
下载并安装Memcache服务器端服务器端主要是安装memcache服务器端.下载:http://www.danga.com/memcached/dist/memcached-1.2.2.tar.gz ...
- linux上的文件服务
主要的文件服务vsftp.Samba.NFS对比 服务器名称 用户客户端平台 使用范围 服务端口 VSFTP Windows/linux/unix/macOS等 发布网站,文件共享 Tcp/21 Sa ...
- linux上安装telnet服务
[LINUX] 使用yum 安装.开启 telnet 服务 pasting 一.安装telnet 1.检测telnet-server的rpm包是否安装 [root@localhost ~]# rpm ...
- 远程连接Linux上的MongoDB服务
1.Linux环境上安装好MongoDB,并配置好环境变量 2.启动MongoDB 注:mongod /opt/michael/mongodb/mongodb-linux-x86_64-4.0.5/d ...
随机推荐
- OpenCV Java Tutorials- Camera Calibration
2020-10-10原文地址:https://opencv-java-tutorials.readthedocs.io/en/latest/09-camera-calibration.html#id1 ...
- SpringBoot+单机redis
spring boot-redis集成 看教程来的,看起来很简单,但是集成后发现启动失败? WARN 2556 --- [ restartedMain] ationConfigEmbeddedWebA ...
- eclipse 配置opencv
1 准备 eclipse 2017 JDK1.8 opencv 4.40 2 配置 新建java工程 添加jar包 选择opencv-xxx.jar包 加入原生库 选择原生库位置 确认即可,测试 新建 ...
- 多测师讲解pthon_002字符,列表,元组,字段等
# # # 索引:# # # 正向索引: 0 1 2 3 4 5 6# # # l= a b c d e f g# # # 反向索引: -7 -6 -5 -4 ...
- 数据结构&算法的引言&时间复杂度
什么是计算机科学? 首先明确的一点就是计算机科学不仅仅是对计算机的研究,虽然计算机在科学发展的过程中发挥了重大的作用,但是它只是一个工具,一个没有灵魂的工具而已.所谓的计算机科学实际上是对问题.解决问 ...
- Redis不重启的情况下 切换持久化模式
确保redis版本在2.2以上 [root@localhost /]# redis-server -v Redis server v=4.0.10 sha=00000000:0 malloc=jema ...
- 基于python实现顺序存储的栈
""" 栈 sstack.py 栈模型的顺序存储 重点代码 思路总结: 1.列表是顺序存储,但功能多,不符合栈的模型特征 2.利用列表,将其封装,提供接口方法 " ...
- [wxpusher]分享一个服务器推送消息到微信上的小工具,可以用于微信推送提醒和告警。
背景 作为一个程序员,业余搞点自己的东西很正常,一般程序员都会有一两台自己的服务器,谁叫今天xx云搞活动,明天yy云搞活动呢. 自家的服务器用来跑爬虫,跑博客,或者跑一些个人业务,但当服务有新状态,抢 ...
- nginx优化:配置gzip压缩页面提高访问速度(nginx1.18.0)
一,为什么nginx要使用gzip 1,压缩的作用: 页面使用gzip压缩之后, 页面大小可以压缩到原来的1/7左右, 传输速度和页面打开时间都可以大幅度提高, 有利于用户访问页面体验的提升 2,Ng ...
- PyTorch常用参数初始化方法详解
1. 均匀分布 torch.nn.init.uniform_(tensor, a=0, b=1) 从均匀分布U(a, b)中采样,初始化张量. 参数: tensor - 需要填充的张量 a - 均匀分 ...