瞭解 OpenResty XRay 是如何做到幫助企業定位應用程式存在的問題以及最佳化其效率的。

瞭解更多 LIVE DEMO

對於像 OpenResty 和 Nginx 這樣的非阻塞 Web 伺服器來說,消耗大量 CPU 資源是很常見的。這要歸功於作業系統特性如 epollkqueue 的 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.profilehost 列是來自 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.orgdoc.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+1eBPF2 後端執行這些工具,這兩種後端都使用了 100% 非侵入式的動態追蹤技術,基於 Linux 核心的 uprobeskprobes 功能。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、LuaJITGDBSystemTapLLVM、Perl 等,並編寫過 60 多個開源軟體庫。

關注我們

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

我們的微信公眾號

翻譯

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


  1. Stap+ 是 OpenResty Inc 對 SystemTap 的大幅增強版本。 ↩︎

  2. 這實際上是 OpenResty Inc 大幅增強的 eBPF 實現,稱為 ORBPF。 ↩︎