分析 OpenResty 或 Nginx 中最耗 CPU 的請求
對於像 OpenResty 和 Nginx 這樣的非阻塞 Web 伺服器來說,消耗大量 CPU 資源是很常見的。這要歸功於作業系統特性如 epoll
和 kqueue
的 I/O 多路複用功能。有時,對於 DevOps 和 SRE 人員來說,快速精確地找出線上伺服器或多個伺服器中消耗最多 CPU 時間 的請求 URI 或請求主機名是很有幫助的。在本文中,我們將演示如何使用 OpenResty XRay 中的動態追蹤工具,實時分析未經修改的 OpenResty 和 Nginx Web 伺服器以獲取此類統計資料。
我們將使用標準動態追蹤工具和透過類 SQL 語言(稱為 YSQL)建立的自定義工具,展示真實世界的示例,包括由 OpenResty XRay 自動生成的資料和圖表。
系統環境
在此,我們以 Red Hat Enterprise Linux 7 系統為例。任何受 OpenResty XRay 支援的 Linux 發行版都應同樣適用,如 Ubuntu、Debian、Fedora、Rocky、Alpine 等。
我們使用未經修改的開源 OpenResty 二進位制構建作為目標應用。您可以使用任何 OpenResty 或 Nginx 二進位制檔案,包括您自己編譯的版本。不會向現有的執行程序插入程式碼,也不要求軟體編譯帶上特殊的編譯選項,或者載入特定的外掛或者共享庫檔案。這正是 動態追蹤 技術的優勢所在。它是真正非侵入式的。
我們還在同一系統上執行 OpenResty XRay 的 Agent 守護程序,並已 安裝和配置 了 openresty-xray-cli
包中的命令列工具。
CPU 佔用最高的請求主機名
使用標準工具
最便捷的方法是直接執行標準工具 ngx-cpu-hottest-hosts
。
我們首先需要找出 OpenResty 或 Nginx 伺服器例項的主程序 PID。
$ ps aux | grep nginx:
root 1691450 0.0 0.0 28868 4140 ? Ss Jul05 0:00 nginx: master process /usr/local/openresty/nginx/sbin/nginx
nobody 3055159 1.5 0.0 40868 4096 ? S 14:38 4:58 nginx: worker process
主程序的 PID 是 1059。我們使用這個 PID 來追蹤該程序組中的所有程序,包括 Nginx 工作程序。
$ orxray analyzer run ngx-cpu-hottest-hosts -p -1691450 -t 10
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/582346 for charts
在此,我們使用 orxray
命令列工具來執行標準工具 ngx-cpu-hottest-hosts
,針對由主程序 PID 1059 指定的程序組,透過 -p
選項進行操作。請注意 PID 前的減號,它表示我們要實時跟蹤該程序的整個程序組。同時,-t
選項指定了我們希望跟蹤的秒數。作為一般經驗法則,當目標應用不太繁忙時,我們應使用較長的取樣時間視窗;而對於較繁忙的應用,則使用較短的視窗。
上述輸出顯示了一個連結,指向 OpenResty XRay 的 Web 控制檯,我們可以在那裡看到為此次執行生成的精美圖表。不過,您的 Web 控制檯 URI 可能會有所不同。
我們可以看到,最熱門的是 openresty.org
主機名。其次是 openresty.com
。請記住,我們這裡只計算了命中作業系統 CPU 分析器 的請求,而不是所有請求。因此,只有相對數值才有意義。例如,考慮到它們的樣本計數分別為 733 和 612,openresty.org
消耗的 CPU 時間比 openresty.com
多約 19%。
有時,我們可能只想分析單個 Nginx 工作程序,這種情況可能發生在某個工作程序消耗的 CPU 時間比其他程序多,或者我們想要最小化引入的跟蹤開銷時。在這種情況下,我們可以使用該工作程序的 PID 作為 orxray
命令的 -p
選項的值,如下所示:
$ orxray analyzer run ngx-cpu-hottest-hosts -p 3055159 -t 10
這次請務必省略 PID 前的減號(-
)。
預設情況下,該工具分析當前機器上的程序。如果您想分析其他伺服器上的程序,可以新增 -a agent_ID
選項來指定您想要執行的伺服器。只需使用 orxray agent list
命令獲取您的 OpenResty XRay Web 控制檯可見的代理 ID 列表。
使用 YSQL 建立自定義工具
使用名為 YSQL 的類 SQL 語言建立自定義動態跟蹤工具可以獲得最大的靈活性,這更有趣。YSQL 語言從不用於查詢任何關聯式資料庫;相反,它始終被編譯為動態跟蹤工具,用於對實時程序和執行中的應用進行實時檢查和分析。
讓我們建立一個名為 my-cpu-hottest-hosts.ysql
的純文字檔案,內容如下。請隨意使用您喜歡的程式碼編輯器。
select count(*) count, host
from cpu.profile inner join ngx.reqs
group by host
order by count desc
limit 10;
SQL 查詢大部分是自解釋的。最有趣的部分是 from
子句,它使用 inner join
將 Nginx 請求與作業系統的 CPU 分析器進行計數。CPU 分析器對應於虛擬表 cpu.profile
。host
列是來自 HTTP host 頭的值。我們新增了 limit 10
子句,因為我們只關心前 10 個。
現在讓我們執行這個 YSQL 工具。假設工作程序的 PID 是 3055159,我們有以下命令。
$ run-ysql -p 3055159 ./my-cpu-hottest-hosts.ysql -t 10
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/583188 for charts
請注意,這次我們使用 run-ysql
命令列工具。
我們可以瀏覽網頁連結,檢視與上面標準工具類似的輸出圖表。
單行 YSQL
我們還可以將 YSQL 作為單行命令執行,無需建立本地檔案。
$ run-ysql -p 3055159 -t 10 -e 'select count(*) count, host from cpu.profile inner join ngx.reqs group by host order by count desc limit 10;'
CPU 開銷最高的請求 URI
我們還可以追蹤目標程序中 CPU 佔用最高的請求 URI。
使用標準工具
我們可以執行標準工具 ngx-cpu-hottest-uris
:
$ orxray analyzer run ngx-cpu-hottest-uris -p 3055159 -t 10
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/622478 for charts
我們可以看到 CPU 佔用最高的前兩個請求 URI 分別是 openresty.org
的 /
和 openresty.com
的 /en
。
建立自定義 YSQL 工具
這次的 YSQL 查詢略有不同。我們使用 uri
列代替。
select count(*) count, host, uri
from cpu.profile inner join ngx.reqs
group by host, uri
order by count desc
limit 10
現在讓我們執行這個 YSQL 工具。假設工作程序的 PID 是 3055159,我們有以下命令。
$ run-ysql -p 3055159 ./my-cpu-hottest-uris.ysql -t 10
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/622204 for charts
我們可以瀏覽網頁連結,檢視與上述自定義工具類似的輸出圖表。
深入探究
主機名或 URI 佔用更多 CPU 資源的一個自然原因是它們的請求數量比其他的多。我們可以透過在一個時間視窗內按主機名或 URI 分組計算所有請求來驗證這一點。
請求最多的最繁忙主機名
使用標準工具
我們可以使用標準工具 ngx-req-counts-by-hosts
進行計數。
$ orxray analyzer run ngx-req-counts-by-hosts -p 3055159
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/584324 for charts
我們可以按照指示瀏覽網頁:
我們可以看到,排名第一的域名 openresty.org
也擁有最多的請求。但第二位是 doc.openresty.com
而不是 openresty.com
。這意味著平均而言,openresty.com
的每個請求可能比 doc.openresty.com
的請求消耗更多的 CPU 時間。
使用 YSQL 建立自定義工具
僅出於演示目的,我們可以建立一個簡單的 YSQL 工具檔案,以建立一個模擬標準工具 ngx-req-counts-by-hosts
的自定義工具:
select count(*) count, host
from ngx.reqs
group by host
order by count desc
limit 10;
請注意 from
子句。我們不再與虛擬表 cpu.profile
進行 inner join
。因此,現在我們統計的是在取樣時間視窗內 Nginx 或 OpenResty 處理的所有請求。
現在讓我們針對 PID 為 3055159
的 Nginx 工作程序執行這個 YSQL 工具。
$ run-ysql -p 3055159 ./top-10-hosts-req.ysql
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/584615 for charts
我們將得到一個類似於上面所示條形圖的圖表。
網路資料量最大的最繁忙主機名
我們還有 ngx-req-size-by-hosts
標準工具,用於取樣具有大量累積網路流量資料(或請求大小,包括請求頭和請求體)的最繁忙請求主機名。
$ orxray analyzer run ngx-req-size-by-hosts -p 3055159
Start tracing...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/584675 for charts
我們可以看到,openresty.org
和 doc.openresty.com
也佔據了大部分網路資料量,這與請求計數的情況類似。
一個自定義的 YSQL 工具可能如下所示:
select sum(req_size) request_size, host
from ngx.reqs
group by host
order by request_size desc
limit 10;
來自 ngx.reqs
虛擬表的 req_size
列代表總請求大小(請求頭 + 請求體)。但它不包含任何 TLS/SSL 握手流量。
查詢瓶頸並進行最佳化
為了分析具體的效能瓶頸並獲得最佳化建議,我們可以進一步使用 C 層面和 Lua 層面的 CPU 火焰圖工具。
OpenResty XRay 可以自動分析任何繁忙的應用(不僅限於 OpenResty 和 Nginx 應用!),我們的人類專家還可以提供包含可執行建議的豐富分析報告。這樣,普通使用者甚至不需要知道何時何地執行甚麼工具。他們也不需要解釋分析器的輸出。
直接在 Web 控制檯中執行
使用者可以選擇直接在 OpenResty XRay 的 Web 控制檯中執行本教程中涉及的任何工具。它們甚至可以在高 CPU 使用率等有趣事件發生時自動觸發。openresty-xray-cli
中的命令列實用程式對於演示目的很方便。它們也易於自動化,並可由 DevOps 和 SRE 人員整合到其他系統中。
跟蹤容器內的應用
OpenResty XRay 工具支援透明地跟蹤容器化應用。Docker 和 Kubernetes(K8s)容器都可以透明地工作。與普通應用程序一樣,目標容器不需要任何應用或額外許可權。OpenResty XRay Agent 守護程序應該在目標容器外部執行(例如直接在主機作業系統中或在其自己的特權容器中)。
讓我們看一個例子。我們首先使用 docker ps
命令檢查容器名稱或容器 ID。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4465297209d9 openresty/openresty:1.19.3.1-2-alpine-fat "/usr/local/openrest…" 18 months ago Up 11 minutes angry_mclaren
這裡的容器名稱是 angry_mclaren
。然後我們可以找出此容器中目標程序的 PID。
$ docker top angry_mclaren
UID PID PPID C STIME TTY TIME CMD
root 3310154 3310133 0 14:22 ? 00:00:00 nginx: master process /usr/local/openresty/bin/openresty -g daemon off;
nobody 3310209 3310154 0 14:22 ? 00:00:00 nginx: worker process
openresty
工作程序的 PID 是 3310209
。然後我們像往常一樣針對這個 PID 執行 OpenResty XRay 分析器。
$ orxray analyzer run ngx-cpu-hottest-hosts -p 3310209 -t 10
Start tracing...
...
Go to https://x5vrki.xray.openresty.com.cn/targets/68/history/600752 for charts
OpenResty XRay 還能夠自動檢測長時間執行的程序,並將其識別為特定型別的"應用"(如 “OpenResty”、“Python” 等)。
工具的實現方式
所有工具都是使用 Y 語言 實現的。OpenResty XRay 透過 Stap+1 或 eBPF2 後端執行這些工具,這兩種後端都使用了 100% 非侵入式的動態追蹤技術,基於 Linux 核心的 uprobes
和 kprobes
功能。YSQL 查詢首先被編譯成 Y 語言,然後進一步編譯成可執行的動態追蹤工具。
我們不需要目標應用和程序的任何配合。我們不使用也不需要任何日誌資料或指標資料。我們直接以嚴格的只讀方式分析執行中程序的程序空間。而且,我們絕不會向目標程序注入任何位元組碼或其他可執行程式碼。這是 100% 乾淨和安全的。
工具的開銷
本教程中演示的動態追蹤工具非常高效,適合線上執行。
當工具未執行且不進行主動取樣時,對系統和目標程序的開銷嚴格為零。我們從不向目標應用和程序注入任何額外的程式碼或外掛;因此,不存在固有的開銷。
在取樣期間,在典型的伺服器硬體上,請求延遲平均僅增加不到 1 微秒(us)。對於每個 CPU 核心每秒處理數萬個請求的最快 OpenResty/Nginx 伺服器來說,最大請求吞吐量的降低也僅約為 4%。
關於作者
章亦春是開源 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. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!
-
這實際上是 OpenResty Inc 大幅增強的 eBPF 實現,稱為 ORBPF。 ↩︎