记录一次线上进程异常崩溃的排查过程

        7月5日晚上11点收到运维同学的消息,说有一个游戏服进程崩溃了,有产生corefile文件,原本以为gdb bt一下就能很清晰地找到这个问题的原因,但当进行问题排查时,发现事情并没有那么简单。先看一下堆栈图。

        红框部分为逻辑层的最后的函数调用,红框以上部分是c++库函数调用,再怎么怀疑也不能怀疑库函数出问题了吧,于是着重排查红框部分是否有访问非法内存地址。

        回去查看源码,该函数的实现非常简单,就是传入一个根据key在std::map里查找对应的value,那么按照以往经验,情况只有两种可能,一是传入的key是个非法指针(NULL或者野指针),二是类成员变量m_BuffParams所在的地址被写坏了

        虽然gdb中,逻辑层调用栈中的key被优化掉无法打印,但是从传入至map的参数可以看到,该key是有效字符串,并不是NULL或者野指针,因此可以排除这种情况。那么接下来就要怀疑m_BuffParams是不是被写坏了,于是打印该成员变量:

发现该成员变量也是完整的,说明内存没有被写坏。这就有点出乎我的意料了,内存既然没有被写坏,那为何会产生宕机呢?于是我去查看系统的syslog关于宕机的信息:

这条日志有这么几个信息点:

1.系统抛出的错误码error值为0(后面会讲这个error值是什么意思)

2.错误关键信息为trap invalid op code,并非segfault。

3.导致宕机的地方libc-2.23.so这个动态链接库中,崩溃代码相对地址为0x16fa4a(0x7fa01036da41-0x7fa0101fe0000)

信息收集到了,那么接下来我们可以做进一步分析了。先看error值,一般如果是我们在逻辑函数中将内存写坏,error值通常为4或者6,那么这个error值是什么意思呢,这里直贴一个结论:

具体关于error值的讨论可以参考这篇文章:

https://worthsen.blog.csdn.net/article/details/106896795

之前我们之所以逻辑层写坏内存导致宕机error为4(00000010)或者6(00000110),是由于我们写坏或者读取的是用户态内存段。而这一次报的错误,首先并非通常碰到的segfault,而是内核态读操作trap invalid opcode导致。百度搜了一下关于trap invalid opcode的信息,少之又少。只有一篇与我们这次宕机非常相似的文章:

https://cloud.tencent.com/developer/article/1356935

大致的意思是,由于指令集不一致导致宕机。那么我们接下来分析的重点就是指令集这一部分了,我们首先要去查看,宕机的地方到底是用来什么汇编指令。于是我们需要将lib-2.23.so这个动态链接库进行反汇编处理:

objdump -D /lib/x86_64-linux-gnu/libc-2.23.so > libc.objdump

查看生成后的汇编文件,并定位到出错的那个地址(0x16fa4a)。

我们发现,该地址的指令非常简单,就是cmp,即对两个寄存器中的内容进行比较,因此肯定不是因为无法识别指令导致。但此时我又怀疑是不是由于我找错了地方,为了验证程序就是在此处崩溃,我又回头去看了下堆栈信息的最顶部,当即的代码是发生在memcmp-sse4.S文件的1577行:

我决定将libso的源码下载下来,再与我们的反汇编文件进行比较,如果二者一致,说明一定是在这个地方崩溃的。

在github上很容易搜到源码,于是我们定位到1577行,并查看上下文,发现就是反汇编后在0x16fa4a地址的那段代码,因此可以确定的确是在cmp %cl,%al这个地方崩的,gdb查看这两个寄存器中的内容,发现也是合法值。此时我有些没有头绪了,既然全部合法(地址合法,指令合法),程序为何会崩溃?无奈只能求助我们的CTO,经过一番讨论后,开始怀疑是云服务商的提供的Linux版本内核有问题(毕竟不是真实物理机,而是云服务虚拟机),并且之前也碰到过类似的问题,最终通过升级内核版本解决的问题。如果真是该问题,那么显然已经超过了我们能够解决的范畴了,我们只能收集信息并反馈给云服务商。

        此次问题记录,不光是为了收集信息,更多其实是想要总结一下进程崩溃时,排查崩溃原因的基本思路(通过coredump文件查看堆栈,通过syslog查看崩溃地址与error值,通过反汇编文件查看崩溃程序段汇编源码)。

        很多时候,书本上的知识只能为我们提供理论依据,真正能够帮助我们提高问题解决能力的,还是要通过不断的进行实践才行,因此每当遇到问题时,我们都需要好好把握住这次解决问题的机会。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
线上内存飙升是一个比较严重的问题,如果不及时处理,可能会导致系统崩溃。以下是一般的排查问题的过程: 1. 监控告警分析:系统应该有监控告警机制,如果内存使用率过高,应该及时发出告警并记录监控数据。首先,需要分析告警信息和监控数据,确认内存使用率确实出现了异常。 2. 定位问题代码:通过监控工具、日志和代码调试等方法,确定哪些代码出现了内存使用率飙升的问题。可以使用 JVM 的内存分析工具,例如 jmap、jhat、jstack、VisualVM 等来分析内存使用情况,并找出内存泄漏的代码位置。 3. 解决问题代码:根据定位出的代码问题,进行修复。对于内存泄漏问题,需要分析代码中的对象生命周期,释放不再使用的对象,并检查是否存在对象引用未释放的情况。对于频繁创建和销毁对象、大对象等问题,需要优化代码逻辑,减少内存占用。 4. 测试验证:完成修复后,需要进行测试验证,确保问题得到了解决,并且没有引入新的问题。 5. 监控预警优化:针对该问题,需要优化监控预警机制,避免类似问题再次出现。可以增加更加详细的监控数据、设置更加敏感的告警阈值等等。 总之,线上内存飙升是一个比较严重的问题,需要及时发现、定位、修复和验证。同时,也需要优化监控预警机制,避免类似问题再次出现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值