從 9萬 QPS 到 6千:一次壓測暴露的 15 倍效能黑洞,我們如何用 OpenResty XRay 定位根因
一個微秒量級的反向代理環節,在特定條件下產生了 93% 的效能損耗,且常規監控指標呈現出虛假的“一切正常”。這是一個典型的觀測盲區,也是系統性雪崩的隱患。本文覆盤了一次從 15 倍效能差距最佳化至 10% 預期損耗的深度調優。相比單純的修復,我們更關注如何用 OpenResty XRay 穿透編譯器行為與連線管理的底層瓶頸。在現代高併發架構中,對工程細節的掌控力,直接決定了基礎設施的穩定性邊界。
93% 損耗背後的觀測盲區
在任何成熟的工程團隊中,效能驗收通常是一個確定性的、流程化的環節。尤其對於閘道器這類基礎元件,其架構(Client → OpenResty Gateway → Upstream)已經是一個被反覆驗證的成熟模式。理論上,一個僅做輕量級轉發的閘道器,其效能開銷應是可預測且極低的。
然而,在對新版閘道器進行基準壓測時,我們遭遇了驚人的效能衰退:
- 上游服務基線 (直連壓測): 94,706 QPS
- 新版閘道器 (反向代理): 6,301 QPS
效能憑空蒸發了 93%。一個簡單的反向代理,竟然造成了近 15 倍的效能差距。系統表面上風平浪靜:沒有錯誤日誌,配置也符合常規認知,問題顯然已經下沉到我們日常觀測的視野之外。
OpenResty XRay 揭示連線複用問題
我們使用 OpenResty XRay 對閘道器進行 CPU 效能分析,執行 lj-c-on-cpu 工具生成火焰圖:
CPU 火焰圖被兩大塊異常寬闊的平臺所佔據:connect() 和 close() 系統呼叫。
在高效能網路服務中,這兩者本應是幾乎不可見的“背景噪音”。它們的異常凸顯,指向一個致命的問題:上游連線沒有被複用。每一個進來的請求,都在觸發一次全新的 TCP 握手和揮手。在高併發場景下,這無異於一場“連線風暴”,核心將大量時間消耗在建立和銷燬連線上,而非真正的資料處理。
透過 OpenResty XRay 提供的完整呼叫棧,我們迅速鎖定了問題根源:
- Connect 路徑:
ngx_http_proxy_handler→ngx_http_upstream_connect→connect() - Close 路徑:
ngx_http_upstream_finalize_request→ngx_close_connection→close()
診斷清晰明瞭:我們的 upstream 配置塊中,遺漏了 keepalive 指令。這是一個看似微小、卻足以在生產環境中引發雪崩的配置疏忽。
我們立即啟用了上游 keepalive。效果立竿見影:效能提升:從 6,301 QPS 到 21,923 QPS,提升 3.48 倍!
connect() 和 close() 的尖峰已然消失。第一個效能黑洞被填補,但故事還未結束。
對比分析發現編譯選項問題
儘管效能大幅回升,但資深的工程師直覺告訴我們,事情沒那麼簡單。我們將當前版本的效能(21,923 QPS)與上一個穩定版本(24,115 QPS)進行對比,發現仍然存在約 10% 的效能差距。
這 10% 的差距從何而來?它雖然不像 15 倍的鴻溝那樣觸目驚心,但對於追求極致效能的基礎設施而言,任何不明不白的衰退都是不可接受的。
- 當前版本的火焰圖“更深”:呼叫棧的層級明顯多於穩定版本。
- 特定函式呼叫增多:例如,
ngx_http_gunzip_body_filter這樣的函式在呼叫鏈中頻繁出現,而在穩定版本中則幾乎不可見。
檢視 ngx_http_gunzip_body_filter 的程式碼:
static ngx_int_t
ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int rc;
ngx_uint_t flush;
ngx_chain_t *cl;
ngx_http_gunzip_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_gunzip_filter_module);
if (ctx == NULL || ctx->done) {
return ngx_http_next_body_filter(r, in);
}
}
理論上,Nginx/OpenResty 的 filter 鏈大量使用了尾呼叫(tail-call),在最佳化編譯下,這些呼叫應該被編譯器“拉平”,幾乎沒有額外開銷。而當前版本的火焰圖形態,恰恰暗示著編譯器最佳化可能失效了。
編譯器選項對指令執行效率的影響
順著這條線索,我們核查了兩個版本的構建指令碼,發現:
當前開發版本使用了 -O0 編譯選項。
原因是在開發過程中,為了方便除錯某個問題,臨時將編譯最佳化關閉了。但在功能開發完成後,忘記恢復為最佳化編譯選項。
-O0 意味著:
- 函式內聯失效 - 小函式呼叫無法被內聯
- 尾呼叫最佳化失效 - 呼叫棧變深
- 冗餘程式碼未消除 - 更多無用指令
- 暫存器使用效率低 - 更多記憶體訪問
這些看似微小的編譯器行為差異,累積起來,不多不少,恰好“偷”走了我們 10% 的效能。
我們將編譯選項恢復為標準的 -O2,重新構建並部署。
結果顯示效能完全恢復,與穩定版本持平。至此,兩個效能問題被徹底解決。
15 倍 QPS 差異的工程性覆盤
這次從 94K QPS 到 6K QPS 的效能排查,暴露了現代複雜系統中兩個深刻的挑戰:
“隱形上下文”的漂移:效能不僅由程式碼邏輯決定,更取決於構建與執行時環境的“隱形上下文”——例如編譯選項、核心引數和執行時配置。這些上下文的變化往往在 Code Review 中難以察覺,卻能導致災難性的後果。本次的
keepalive缺失和-O0編譯選項就是最好的例證。突破觀測盲區:為何你需要動態追蹤?當問題下沉至核心與編譯器層面,傳統的 Logs & Metrics 往往保持靜默。 本案例證明,面對系統級瓶頸,我們需要的是 OpenResty XRay 這樣具備穿透力的工具:
- 全鏈路取樣:穿透應用層直達核心,快速識別宏觀瓶頸(如連線風暴)
- 異常模式識別:透過火焰圖快速識別非預期的 connect/close 路徑。
- 基線對比:定位微觀層面的細微差異(如編譯器行為)
效能問題往往不是非黑即白的 Bug,而是灰度的效率流失。 在複雜的系統架構中,僅憑經驗猜測是低效的。我們需要透過 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、LuaJIT、GDB、SystemTap、LLVM、Perl 等,並編寫過 60 多個開源軟體庫。
關注我們
如果您喜歡本文,歡迎關注我們 OpenResty Inc. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!



















