首页 > 数据库 > 国内数据库 > 【建议收藏】进程崩溃定位难?日志分析五步安!
作者:胡呈清,爱可生 DBA 团队成员,擅长故障分析、性能优化,个人博客:[简书 | 轻松的鱼],欢迎讨论。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 1400 字,预计阅读需要 5 分钟。
OBServer 进程 Crash(崩溃退出)的常见的原因有:程序 bug、文件损坏、磁盘坏块、内存坏块,是一种比较难分析的故障。
集群部署时会自动配置 coredump 文件,因此发生 Crash 会自动生成 coredump 文件(捕获进程崩溃时内存的文件)。它包含程序在失败时的状态快照、所有线程的堆栈信息,可用于调试,是用来分析 Crash 问题的最佳工具。
但某些时候, coredump 文件 不一定能顺利生成,这个时候就需要从 observer.log 中获取崩溃时的堆栈,分析崩溃位置的代码,以此来寻找原因。本文介绍的就是这个方法。
本文发布时,该方法适用于 OceanBase 的所有版本。
OBServer 在 Crash 后会在 observer.log 里打这么一段类似的日志,基本上你只要去搜索 “CRASH ERROR” 关键字就行:
CRASH ERROR!!! sig=11, sig_code=2, \ sig_addr=7f3edd31dffb, timestamp=1725496052323606, \ tid=57605, tname=TNT_L0_1002, \ trace_id=20970917872454-1707004480400037, \ extra_info=((null)), lbt=0x9baead8 \ 0x9b9f358 0x7f43d58e562f \ 0x7f43d52525fc 0x95eeda9 \ 0x95ec568 0x95e6c0c \ 0x95e4c33 0x9cbf4c7 \ 0x93be9ee 0x939e320 \ 0x93bd64e 0x939c105 \ 0x939c6e6 0x2cff1c1 \ 0x9918a74 0x9917461 0x9913f1e
这里手动增加换行,提高阅读性
堆栈信息可以通过解析内存地址得到(每个内存地址对应一个栈桢):
addr2line -pCfe /home/admin/oceanbase/bin/observer \ 0x9baead8 0x9b9f358 0x7f43d58e562f 0x7f43d52525fc \ 0x95eeda9 0x95ec568 0x95e6c0c 0x95e4c33 0x9cbf4c7 \ 0x93be9ee 0x939e320 0x93bd64e 0x939c105 0x939c6e6 \ 0x2cff1c1 0x9918a74 0x9917461 0x9913f1e
这里手动增加换行,提高阅读性
输出如下:
ObMPStmtExecute::copy_or_convert_str 这个函数safe_backtrace at ??:?
oceanbase::common::coredump_cb(int, siginfo_t*) at ??:?
?? ??:0
?? ??:0
oceanbase::observer::ObMPStmtExecute::copy_or_convert_str(oceanbase::common::ObIAllocator&, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, oceanbase::common::ObString const&, oceanbase::common::ObString&, long) at ??:?
oceanbase::observer::ObMPStmtExecute::parse_basic_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::common::ObObj&) at ??:?
oceanbase::observer::ObMPStmtExecute::parse_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::sql::TypeInfo*, oceanbase::sql::TypeInfo*, oceanbase::common::ObObjParam&, short) at ??:?
oceanbase::observer::ObMPStmtExecute::before_process() at ??:?
oceanbase::rpc::frame::ObReqProcessor::run() at ??:?
oceanbase::omt::ObWorkerProcessor::process_one(oceanbase::rpc::ObRequest&, int&) at ??:?
oceanbase::omt::ObWorkerProcessor::process(oceanbase::rpc::ObRequest&) at ??:?
oceanbase::omt::ObThWorker::process_request(oceanbase::rpc::ObRequest&) at ??:?
oceanbase::omt::ObThWorker::worker(long&, long&, int&) at ??:?
non-virtual thunk to oceanbase::omt::ObThWorker::run(long) at ??:?
oceanbase::lib::CoKThreadTemp<oceanbase::lib::CoUserThreadTemp<oceanbase::lib::CoSetSched> >::start()::{lambda()#1}::operator()() const at ??:?
oceanbase::lib::CoSetSched::Worker::run() at ??:?
oceanbase::lib::CoRoutine::__start(boost::context::detail::transfer_t) at ??:?
trampoline at safe_snprintf.c:?如何确认具体执行到
ObMPStmtExecute::copy_or_convert_str 函数的哪一行?需要在 debug 版本上使用
gdb (要求不低于 9.0 版本)来解析内存地址:
##下载对应版本的 debug 安装包(企业版需要问官方获取) https://mirrors.aliyun.com/oceanbase/community/stable/el/7/x86_64/ ##安装debug包 rpm2cpio oceanbase-ce-debuginfo-3.1.5-100010012023060910.el7.x86_64.rpm |cpio -div ##然后用gdb打开二进制文件 gdb ./usr/lib/debug/home/admin/oceanbase/bin/observer.debug ##解析内存地址 (gdb) list *0x95eeda9 0x95eeda9 is in oceanbase::observer::ObMPStmtExecute::copy_or_convert_str(oceanbase::common::ObIAllocator&, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, oceanbase::common::ObString const&, oceanbase::common::ObString&, long) (./src/observer/mysql/obmp_stmt_execute.cpp:1428). (gdb) list *0x95ec568 0x95ec568 is in oceanbase::observer::ObMPStmtExecute::parse_basic_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::common::ObObj&) (./src/observer/mysql/obmp_stmt_execute.cpp:1237). (gdb) list *0x95e6c0c 0x95e6c0c is in oceanbase::observer::ObMPStmtExecute::parse_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::sql::TypeInfo*, oceanbase::sql::TypeInfo*, oceanbase::common::ObObjParam&, short) (./src/observer/mysql/obmp_stmt_execute.cpp:1372). (gdb) list *0x95e4c33 0x95e4c33 is in oceanbase::observer::ObMPStmtExecute::before_process() (./src/observer/mysql/obmp_stmt_execute.cpp:512). 507 in ./src/observer/mysql/obmp_stmt_execute.cpp
拓展阅读:
本案例的调用栈为:
... ->ObMPStmtExecute::before_process() -->ObMPStmtExecute::parse_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::sql::TypeInfo*, oceanbase::sql::TypeInfo*, oceanbase::common::ObObjParam&, short) --->ObMPStmtExecute::parse_basic_param_value(oceanbase::common::ObIAllocator&, unsigned int, oceanbase::common::ObCharsetType, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, char const*&, oceanbase::common::ObTimeZoneInfo const*, oceanbase::common::ObObj&) ---->ObMPStmtExecute::copy_or_convert_str(oceanbase::common::ObIAllocator&, oceanbase::common::ObCollationType, oceanbase::common::ObCollationType, oceanbase::common::ObString const&, oceanbase::common::ObString&, long)
最后崩溃在
ObMPStmtExecute::copy_or_convert_str 函数,代码位置
obmp_stmt_execute.cpp:1428。

ObMPStmtExecute::copy_or_convert_str 函数的主要功能是根据给定的字符集类型,将输入的字符串 src (statement协议里的请求参数)进行复制或字符集转换,并将结果保存在 out 中。崩溃信息中
sig=11,也就是 signal 11,表示程序访问了无效的内存地址,通常是由于空指针引用或者访问了已经释放的内存。
崩溃位置代码
MEMCPY(buf + extra_buf_len, src.ptr(), src.length()); 意思是:通过
MEMCPY 函数将源字符串的内容复制到分配的内存区域中:
extra_buf_len)。所以这里基本可以确认
src.ptr() 是个空指针,如果有
coredump 文件,只需要用
gdb 打印一下这个指针变量就知道了。
然后带着 copy_or_convert_str 关键字(也就是崩溃的那个函数)搜一下官方的知识库,找到对应了的 bug。
崩溃位置的这段代码的逻辑与 bug 描述吻合:在处理 execute 协议时,send long data 协议还没有把 param_data 信息处理完,因此 execute 协议在转换 param_data时读到了空指针,引发了 crash。
通常,按照以上五个步骤对日志进行分析,可以快速定位导致 OBServer 进程 Crash 的原因。希望本文对你有所帮助~
来自 “ ”, 原文作者: ;原文链接:,如有侵权,请联系管理员删除。