自动分析 Core Dump(使用 OpenResty XRay)
自动 core dump 分析把崩溃进程的 core 文件交给工具,由工具重建进程在崩溃那一刻正在做什么——而不需要您在 GDB 里手动逐层排查。OpenResty XRay 就是为崩溃的 OpenResty/Nginx 应用做这件事:把它指向 core 文件,它就会返回一份完整的报告——C 和 Lua 调用栈、精确的崩溃源代码行、Lua 协程分析、Lua GC 对象引用图、libc 内存分配分析,以及崩溃时正在处理的并发 HTTP 请求——全程无需手动使用 GDB。完整的分步演示请观看本文顶部的视频。
定位 OpenResty/Nginx 的 core dump 文件
当 OpenResty 或 Nginx 应用的某个 worker 进程崩溃时,Linux 内核会写出一个 core dump 文件。在这台崩溃的服务器上,worker 进程在用户的 home 目录下留下了一个 core.175276 文件——用 ls 就能找到它,再用 readlink -f 得到它的绝对路径。复制这个路径即可;OpenResty XRay 会就地分析该文件,因此无需移动它,也无需手动匹配相关的库文件。
在 OpenResty XRay 中启动引导式 core dump 分析
在浏览器中打开 OpenResty XRay 的 Web 控制台,选择目标机器(这里是 biz-app-server),进入 Guided Analysis(引导式分析)页面。问题类型选择 Core dumps or process crashes(core dump 或进程崩溃)。
粘贴 core 文件路径。XRay 读取该 core dump,自动提取可执行文件路径(/usr/local/openresty/nginx/sbin/nginx)和应用类型(OpenResty),然后开始分析。如果二进制被 strip、调试符号缺失,XRay 会先自动重建缺失的调试符号——无需安装 nginx-dbg 包,也无需重新编译——下文的崩溃报告依然能解析出真实的函数名与源码行。
解读崩溃报告:信号、寄存器与 C 调用栈
报告首先展示执行上下文。该 worker 进程被 SEGV 信号中止——SEGV 是 “Segmentation Violation”(段错误)的缩写,通常表示发生了非法的内存访问。
在机器码层面,XRay 用红色箭头标出了导致出错的那条指令——mov ecx, DWORD PTR [rsi+rdx*1-0x4]。
XRay 还捕获了崩溃发生那一刻的所有 CPU 寄存器。rsi 和 rdx 的值都是 0x4,因此这条指令的源地址 [rsi+rdx*1-0x4] 计算下来正好是 0x4——一个几乎等于空的地址,正是空指针解引用的典型特征。
C 调用栈解释了执行是如何走到这条指令的。Nginx 的 ngx_http_core_content_phase 通过 ngx_http_lua_run_thread 运行 Lua 内容处理器;随后 LuaJIT 为某个 cdata 类型分发了 FFI 的 __index 元方法,经过 LuaJIT 的 C 类型转换后进入 glibc 的 memcpy——段错误就是在这里触发的。
从 Lua 调用栈定位到精确的崩溃代码行
XRay 直接从 core dump 重建 Lua 层面的调用栈,它是从 Lua CPU 火焰图推导出来的。崩溃的调用路径为 content_by_lua → go(api.lua)→ handle(router/order.lua)→ process_order(order/core.lua:78)→ decode_order_data(order/processor.lua:79)。
它还给出完整的 Lua 调用栈,包含每个函数帧的参数和局部变量,因此您无需复现任何问题就能查看崩溃时的精确状态。
打开 processor.lua 的第 79 行,就能看到出错的语句 order.uid = order_cdata.user_id。order_cdata 本身是一个有效的指针型 cdata 对象,但它保存的 C 指针值为 NULL。读取 order_cdata.user_id 会在这个 NULL 基址上解引用偏移 4,这正是出错地址为 0x4 的原因。修复办法是在访问字段前先用 order_cdata == nil 检查 order_cdata 内部的指针是否为 NULL。
这次崩溃是一次空指针解引用。对于另一类故障——通过“记录与回放”定位的 use-after-free(释放后使用)崩溃——请参阅 从崩溃到根因:OpenResty XRay 如何将 Nginx 内存踩踏问题分析得明明白白。
崩溃时的 Lua 协程、并发 HTTP 请求与 Lua GC 内存
XRay 分析的不止崩溃的那一个协程。它还会分析 core dump 中所有存活的 Lua 协程,并给出其中最常见的 Lua 调用栈——本例中是一条停在 sleep 调用上的代码路径:同样是 process_order 业务代码,正在 ngx.sleep(ngx_http_lua_ngx_sleep)里等待。
报告还捕获了所有正在处理的 HTTP 请求。崩溃 worker 当时正在处理的请求是 POST https://e.woniu.com:1443/order/api(客户端 127.0.0.1,curl/7.76.1),同时还有三个并发的 GET /order/api?request_type=search_orders 请求。
在内存方面,XRay 对最热的 Lua GC 对象引用路径进行排序。这里排名第一的路径是 registry → _LOADED → engines.sre.sre_lib → run_rules,占用了 40.12 MB 存活的 Lua GC 对象——这是从 Lua GC 对象内存分布火焰图中自动推导出来的。
全自动分析与报告
您不必手动运行引导式分析。OpenResty XRay 会监控线上应用产生的新 core dump,自动分析它们,并把结果以日报和周报的形式发布在 Insights 页面上。
正因如此,引导式分析主要适用于应用开发和演示;在生产环境中,自动报告会为您呈现新出现的崩溃。
常见问题
如何从 core dump 中获取 Lua 调用栈?
OpenResty XRay 直接从 core 文件重建 Lua 层面的调用栈,它是从 Lua CPU 火焰图自动推导出来的。它会展示每个 Lua 协程的完整调用栈,包括每个函数帧及其参数和局部变量的值——这些正是您原本需要在 GDB 中手动挖掘的上下文。
LuaJIT 为什么会在 FFI cdata 上发生段错误?
访问一个底层 C 指针为 NULL 的指针型 cdata 的字段,会导致段错误。在这个 core dump 中,order_cdata 是一个有效的 cdata 对象,但它所封装的指针为 NULL;decode_order_data 读取它的 user_id 字段,在 NULL 基址上解引用偏移 4(出错地址 0x4),从而触发 SEGV 并使 worker 进程崩溃。修复办法是在解引用字段之前,用 order_cdata == nil 检查所封装的指针是否为 NULL。
什么信号会触发 OpenResty 或 Nginx 的 core dump?
在这次崩溃中,core dump 是由 SEGV 信号触发的。SEGV 是 “Segmentation Violation”(段错误)的缩写,通常表示发生了非法的内存访问——进程访问了一个不允许它访问的内存地址。OpenResty XRay 会报告确切的信号、出错的指令以及崩溃那一刻的 CPU 寄存器值。
如何找到崩溃的确切 Lua 代码行?
报告会把崩溃的 Lua 函数帧关联回它的源代码。把鼠标悬停在函数的方框上,就会显示源文件及其完整路径,报告还会给出确切的源代码行号。这里指向的是 decode_order_data 的第 79 行,也就是解引用 cdata 内部所封装的 NULL 指针的那一行。
能不能在不手动运行 GDB 的情况下分析 core dump?
可以。OpenResty XRay 会监控线上应用产生的新 core dump,并在 Insights 页面生成以日和周为周期的自动分析报告,因此您无需手动运行引导式分析。在底层,它使用 Y 语言,并根据不同场景在 Stap+、eBPF+、GDB、ODB 等多种运行时之上运行。
关于 OpenResty XRay
OpenResty XRay 是一个动态追踪产品,它可以自动分析运行中的应用程序,以解决性能问题、行为问题和安全漏洞,并提供可行的建议。在底层实现上,OpenResty XRay 由我们的 Y 语言驱动,可以在不同环境下支持多种不同的运行时,如 Stap+、eBPF+、GDB 和 ODB。
关于作者
章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。
章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl 等,并编写过 60 多个开源软件库。
关注我们
如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:
翻译
我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!
































