在開發和維護 OpenResty 應用時,您可能經常面臨這些令人頭疼的情況:Lua 程式碼中的錯誤難以追蹤;效能瓶頸隱藏在複雜的呼叫棧中;生產環境中的偶發性問題幾乎無法在開發環境重現;當應用崩潰時,只留下片段錯誤資訊,無法瞭解完整上下文。傳統除錯工具常常讓我們感到束手無策,一旦錯過關鍵時機,就只能從頭來過,既低效又容易遺漏問題本質。

透過 UDB(Undo Debugger)與 OpenResty XRay 的強大組合,我們終於擁有了在程式執行歷史中自由穿梭的能力,就像擁有了除錯世界的“時光機”。無論是追蹤記憶體分配模式、分析特定請求的執行路徑,還是定位導致崩潰的程式碼片段,這種革命性的除錯方法都能讓您看到傳統工具無法展現的全景檢視。讓我們透過一個 OpenResty 應用的實際案例,一起探索這種突破性技術如何改變我們解決問題的方式。

OpenResty XRay 如何協同 UDB 增效

UDB 如何揭開 OpenResty 應用中 Lua 程式碼的神秘面紗

UDB 作為 Undo 公司推出的時間旅行除錯工具,它為開發團隊提供了前所未有的視覺化能力:

  • 時間維度的探索:告別傳統“重現 - 修復 - 驗證”的繁瑣迴圈。您在程式執行軌跡上自由穿行,捕捉每一個關鍵瞬間。
  • 洞察問題本質:透過智慧斷點和監視機制,直擊異常行為的觸發條件,將模糊的錯誤報告轉化為清晰的問題畫像。
  • 透視執行狀態:實時剖析 Lua 變數和記憶體結構,揭示 OpenResty 應用內部運作機制,快速識別異常模式。
  • Lua 生態完美適配:UDB 與 OpenResty 環境無縫整合,為 Lua 開發者提供了專業級除錯體驗,支援對複雜應用進行立體化分析。

與 OpenResty XRay 強強聯合,打造無死角的除錯體系

OpenResty XRay 能夠自動分析 OpenResty 應用中的 Lua 程式碼執行時的行為,精確定位各類技術痛點。當它與 UDB 聯手時,將為您帶來:

  • 全景式問題診斷:從請求處理到底層執行的立體化檢視
  • Lua 程式碼效能剖析:直觀展現熱點函式和資源消耗
  • 零干擾分析體驗:保持應用原有行為的同時獲取深度洞察
  • 實操導向的最佳化指南:基於真實負載提供針對性改進方案

透過 UDB 與 OpenResty XRay 的協同作用,開發團隊能夠迅速突破技術瓶頸,將複雜的故障排查轉化為清晰的解決路徑。這一組合不僅能夠加速問題解決流程,更能從根本上提升 OpenResty 應用的質量和穩定性,為業務持續創新提供堅實技術保障。

實戰:使用 UDB 與 OpenResty XRay 分析 OpenResty 應用的 Lua 程式碼呼叫棧

下面我們透過一個實際案例,演示如何使用 UDB 精確分析 OpenResty 的 Lua 應用的呼叫棧:

步驟一:錄製應用執行軌跡並重放錄製樣本

首先使用 UDB 的 Live Record 工具錄製 OpenResty 應用的執行過程:

  1. 使用 Live Record 工具錄製一個正在執行的 OpenResty 應用樣本。 1.1 在 OpenResty XRay 的控制檯選擇 現場錄製。 1.2 選擇目標應用和目標程序,單擊 開始錄製。 1.3 單擊 生成錄製檔案 的圖示生成一個錄製檔案。 1.4 生成解釋後單擊 停止錄製 結束錄製過程。 1.5 下載錄製檔案進行分析。

  2. 在 OpenResty XRay 上編譯相關的工具,並將編譯後的工具下載到本地。

  3. 使用 UDB 工具載入錄製樣本,並設定除錯環境:

udb --sessions=no -ex "set pagination off" -ex "set python print-stack full" openresty.rec

步驟二:分析錄製樣本

本文以分析 Lua 記憶體分配為例來介紹 udb 中檢視 OpenResty Lua 的執行呼叫棧。 我們將斷點打在 lua_alloc_realloc 函式。

0% 51> b lj_alloc_realloc
Breakpoint 1 at 0x55560961bca0: file lj_alloc.c, line 1520.
0% 51> c
Continuing.
Thread 1 "nginx" hit Breakpoint 1, lj_alloc_realloc (msp=0x7f5657a9d010, ptr=ptr@entry=0x7f549be49108, nsize=40) at lj_alloc.c:1520
1520    lj_alloc.c: No such file or directory.

步驟三:分析底層 C 呼叫棧

  1. 使用 bt 命令檢視當前的 C 層呼叫棧:
0% 853> bt
#0  lj_alloc_realloc (msp=0x7f5657a9d010, ptr=ptr@entry=0x7f549be49108, nsize=40) at lj_alloc.c:1520
#1  0x000055560961c053 in lj_alloc_f (msp=<optimized out>, ptr=0x7f549be49108, osize=<optimized out>, nsize=<optimized out>) at lj_alloc.c:1582
#2  0x0000555609625270 in lj_mem_realloc (L=0x7f54b4bd1628, p=p@entry=0x7f549be49108, osz=osz@entry=24, nsz=40) at lj_gc.c:883
#3  0x0000555609626e3d in lj_tab_resize (L=0x7f54b4bd1628, t=0x7f54b5065cf0, asize=5, hbits=0) at lj_tab.c:256
#4  0x0000555609626986 in rehashtab (ek=<optimized out>, t=<optimized out>, L=<optimized out>) at lj_tab.c:375
#5  lj_tab_newkey (L=0x7f54b4bd1628, t=0x7f54b5065cf0, key=0x7f549ea60380) at lj_tab.c:453
#6  0x00005556469832df in ?? ()
#7  0x00007ffe8a54b9f0 in ?? ()
#8  0x000055560957e8dd in ngx_lua_conf_ffi_get (keys=<optimized out>, keys_len=0x7f5656ab5dd0, values=0x7f5657a80c78 "x\003\250WV\177", values_len=0x7f5656ab5e70, 
    db=<optimized out>) at ../lua-resty-config-1.0.6/src/ngx_lua_config_module.c:389
#9  0x0000001200000000 in ?? ()
#10 0x00007f549bc917a8 in ?? ()
#11 0x00007f549bc917b6 in ?? ()
#12 0x00007f549cf27568 in ?? ()
#13 0x00007f54b547d508 in ?? ()
#14 0x00007f54b6825e30 in ?? ()
#15 0x00007f549eb0d1a0 in ?? ()
#16 0x00007f549cf275a8 in ?? ()

從 C 呼叫棧可以看到系統底層的 lj_alloc_realloc 函式呼叫被觸發,但這僅顯示了 C 語言層面的資訊,無法直接看到 Lua 業務程式碼的完整呼叫路徑。

步驟四:分析 Lua 程式碼的完整呼叫棧

  1. 載入 OpenResty XRay 提供的 Lua 呼叫棧分析工具:
4% 7,955> source lj-lua-on-cpu.y.py
  1. 使用 lj_lua_on_cpu 命令獲取完整的 Lua 呼叫棧:
0% 853> lj_lua_on_cpu 
C:lj_alloc_realloc
trace#6786:http-runtime-20181201.lua:4028
@1:890
helper_5
@1:1538
[builtin#xpcall]
xpcall
@1:1424
run_access_phase
@edge.lua:187
access
@access_by_lua(nginx.conf:766):2

透過這個完整的 Lua 呼叫棧,我們可以清晰地看到從業務程式碼正在執行 access_by_lua 階段的程式碼。 當前正在執行的是 trace 6786 這個即時編譯的程式碼,這也就是為甚麼前面的 bt 命令獲取的 C 呼叫棧到 ngx_lua_conf_ffi_get 這個函式後就沒有正確展開了。

時間旅行除錯的優勢

UDB 的時間旅行除錯能力是其最強大的特性之一。透過這一功能,我們可以在錄製的執行軌跡中自由地前進或回溯,精確定位到不同的記憶體分配操作時間點,並全面分析每次分配操作的完整上下文和呼叫棧。

為了驗證這一點,我們可以繼續執行程式,捕獲下一個 lj_alloc_realloc 呼叫:

0% 51> c
Continuing.
Thread 1 "nginx" hit Breakpoint 1, lj_alloc_realloc (msp=0x7f5657a9d010, ptr=ptr@entry=0x7f549be49108, nsize=40) at lj_alloc.c:1520
1520    lj_alloc.c: No such file or directory.
1% 849,555> lj_lua_on_cpu 
C:lj_alloc_realloc
trace#177:common-runtime-20181201.lua:393
@common-runtime-20181201.lua:383
bit32_to_strtbl
@common-runtime-20181201.lua:435
inet_to_bitstr
@1:1459
[builtin#xpcall]
xpcall
@1:1424
run_rewrite_phase
@edge.lua:187
access
@access_by_lua(nginx.conf:766):2

透過對比兩次捕獲的呼叫棧,我們可以一目瞭然地發現關鍵差異:

  1. 第一次記憶體分配來自 trace 6786
  2. 第二次記憶體分配則來自 trace 177

這種精準定位能力不僅僅適用於記憶體分配分析,它更是解決複雜問題的利器。無論是分析特定 URI 請求的 Lua 程式碼執行路徑,還是追蹤導致程序崩潰的 Lua 程式碼片段,這種方法都能遊刃有餘地應對。

傳統的 GDB coredump 分析就像是事故現場的一張照片,只能看到最終結果;而 UDB 則像是一部高畫質回放的影片,讓您能夠觀察事故發生前的每一個細節。即使原始程序早已不在執行,您依然可以在完整的程式執行歷史中如魚得水,精確檢視任意時間點的程式狀態與行為細節,真正實現了“時光倒流”式的全方位除錯體驗。

總結

透過本文的實踐探索,我們展示了 UDB 的時間旅行除錯功能與 OpenResty XRay 分析工具的完美結合如何深入剖析 OpenResty 應用中 Lua 程式碼的執行過程。這種組合提供了幾個顯著優勢:

  1. 全面的執行上下文:不僅能看到底層 C 呼叫棧,還能精確追蹤 Lua 業務程式碼的完整呼叫路徑,包括即時編譯(JIT)後的程式碼執行情況。
  2. 時間維度的除錯能力:UDB 允許在程式執行歷史中自由穿梭,無需重啟應用即可分析不同時間點的程式狀態,這對排查間歇性問題和複雜場景尤為重要。
  3. 深度效能分析:結合 OpenResty XRay 的分析工具,可以精確定位效能瓶頸,如記憶體分配模式、熱點函式等。
  4. 事後分析能力:即使在原始程序已經終止的情況下,依然可以透過錄制樣本進行全面分析,這遠超傳統 coredump 分析只能提供崩潰瞬間靜態快照的侷限。

對於追求卓越的軟體開發者和運維專家來說,掌握這種前沿除錯技術不再是可選項,而是在競爭激烈的技術世界中保持領先的必備能力。透過 UDB 和 OpenResty XRay 的強大組合,您能夠以前所未有的精確度理解應用行為,從而構建更加穩定、高效能的應用系統。

關於 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、LuaJITGDBSystemTapLLVM、Perl 等,並編寫過 60 多個開源軟體庫。

關注我們

如果您喜歡本文,歡迎關注我們 OpenResty Inc. 公司的 部落格網站 。也歡迎掃碼關注我們的微信公眾號:

我們的微信公眾號

翻譯

我們提供了 英文版 原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!