自動分析 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. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!
































