跳到內容

效能基準測試

效能數字必須連同量測條件一起解讀。

本頁記錄 2026 年 10 月 11 日至 12 日,在 Apple M2 主機上的 OrbStack 容器環境中進行的效能比較。受測軟體包括 Pingclair、nginx、Caddy 與 Traefik,測試涵蓋反向代理、靜態檔案傳輸、動態 Zstd 壓縮、存取日誌開銷,以及 HTTP/3。

所有結果均來自特定硬體、軟體版本與工作負載下的受控量測。數據反映的是本次實驗條件下的相對表現,不應直接視為其他部署環境的效能預測或容量保證。

本節記錄產生各組數據所使用的硬體、虛擬機、容器配置、軟體版本與測試命令。

四組測試共用相同的虛擬機與容器網路,並使用同一組受測軟體映像,以減少環境差異對結果的影響。

  • 實體主機: MacBook Pro(2022 年),搭載八核心 Apple M2、16 GB 統一記憶體,執行 macOS 27.0.1。
  • 虛擬機: OrbStack 2.2.3,Linux 核心版本為 7.0.14-orbstack,配置 8 vCPU 與 8 GB 記憶體。受測伺服器、負載產生器及後端服務均執行於同一台 Linux VM 內;逐項測試由 VM 內的控制容器負責調度。
  • 容器引擎: Docker 29.4.0(OrbStack engine)。所有容器均連接至專用 bridge 網路 bench-net(192.168.97.0/24),用戶端與伺服器位於同一子網,測試流量不經過外部網路。
元件 版本 映像與建置方式
Pingclair main main@0476be4a(0.0.0-dev) bench/pingclair-main:0476be4a;使用 Rust 1.99.0 執行 cargo build --release --locked
Pingclair v0.2.2 0.2.2 bench/pingclair:0.2.2;採用官方 pingclair-linux-aarch64 發行產物,並已依 SHA256SUMS 驗證
nginx 1.31.6 bench/nginx:1.31.6;由官方原始碼建置,使用 OpenSSL 3.5.5、GCC 15.2,並加入 Zstd 模組
Caddy 2.11.7 官方容器映像 caddy:2.11.7
Traefik v3.7.14 官方容器映像 traefik:v3.7.14

nginx 建置時啟用了以下模組與參數:

--with-http_ssl_module
--with-http_v2_module
--with-http_v3_module
--with-http_realip_module
--with-http_stub_status_module
--add-module=zstd-nginx-module@057a7d3

其中 Zstd 使用第三方模組 tokers/zstd-nginx-module,版本固定於提交 057a7d3。

所有受測容器均使用 linux/arm64 架構,並透過 Docker 的 --cpus=2 限制 CPU 使用量。

容器內的設定檔、測試資料與 TLS 憑證均以唯讀方式掛載。日誌目錄及 nginx 快取目錄則使用各 512 MB 的 tmpfs,避免將持久化儲存裝置的寫入延遲引入測試。

容器啟動參數如下:

終端機視窗
docker run -d --name sut --network bench-net --cpus=2 \
--tmpfs /logs:size=512m \
--tmpfs /var/cache/nginx:size=512m \
-v <bench>/configs:/conf:ro \
-v <bench>/payloads:/payloads:ro \
-v <bench>/certs:/certs:ro \
<image> <server command>

各伺服器均保留自身預設的 worker 或執行緒設定,不強制統一其內部並行模型。例如,nginx 使用 worker_processes auto 與 worker_connections 1024。

TLS 與連接埠

測試使用自簽 TLS 憑證,憑證主體 CN 為 sut,SAN 包含 sut、localhost 與 127.0.0.1。

HTTPS 使用 8443/TCP,HTTP/3 測試另使用 8443/UDP。

靜態檔案

測試包含三種大小的檔案:

檔案 大小
index.html 226 B
small.bin 10 KiB
medium.bin 2 MiB

反向代理後端

後端採用 node:22-slim 容器,啟動四個 Node.js HTTP 服務實例,分別監聽 TCP 3001 至 3004。

各實例的監聽 backlog 設為 4096,並回傳固定的 16 B JSON 回應。

四套反向代理均採用 round-robin 分配請求,並配置上游持久連線重用。nginx 使用 keepalive 64,Traefik 使用 maxIdleConnsPerHost: 64。各實作的連線池語意並非完全相同,因此這些設定代表近似的配置目標,而非內部行為完全等價。

存取日誌

除日誌開銷測試外,所有吞吐量測試均停用存取日誌。

日誌開銷測試分為兩個階段:

  • A:停用存取日誌。
  • B:啟用 JSON 格式的存取日誌,並寫入 512 MB tmpfs。

nginx 使用 escape=json,Pingclair 使用 format json。

動態 Zstd 壓縮

各伺服器採用以下設定:

伺服器 Zstd 設定
Pingclair encode zstd,搭配相同的回應類型匹配條件
nginx zstd_comp_level 3、zstd_min_length 256、zstd_types *
Caddy encode zstd better,並匹配 application/octet-stream

上述設定均啟用動態 Zstd 壓縮,但不同實作的壓縮策略、輸出大小及 CPU 開銷未必完全一致。因此,壓縮組比較的是各伺服器在指定設定下的整體服務吞吐量,而非同一壓縮演算法實作的純計算速度。

HTTP/2

HTTP/2 測試使用 nghttp2 1.68.0 提供的 h2load,執行於 client-lite 容器(Ubuntu 26.04,安裝 nghttp2-client)。

該容器與受測伺服器位於同一個 bridge 網路。

反向代理定點測試:

終端機視窗
h2load -n 500000 -c 100 -t 16 -m 8 \
https://sut:8443/

靜態檔案及日誌開銷測試:

終端機視窗
h2load -n 500000 -c 100 -t 16 -m 8 \
https://sut:8443/index.html

靜態檔案測試分別請求 index.html、small.bin 與 medium.bin。前兩者各發出 500,000 個請求,2 MiB 檔案則為 5,000 個請求。

Zstd 組額外加入以下請求標頭:

終端機視窗
-H 'Accept-Encoding: zstd'

高併發掃描由 benchmark.py 逐點執行:

終端機視窗
h2load -n 20000 -c <c> -t min(c, 8) \
-m 8 -T 5 -N 5 <url>

其中併發數 c 從 1 增加至 9,901,每次遞增 100。每個併發點發出 20,000 個請求。

HTTP/3

HTTP/3 測試使用 Tencent tquic 的 tquic_client,版本為 develop@938e90a,Cargo 套件版本 1.6.0,並使用 BoringSSL 建置。

測試命令:

終端機視窗
tquic_client -t 8 \
--max-concurrent-conns 25 \
--max-concurrent-requests 25 \
--total-requests-per-thread 0 \
-d 10 <url>

本組測試採用每條連線完成一個請求後即重新建立連線的模式,用以觀察 QUIC 連線頻繁建立與關閉時的整體處理能力。

測試調度

高併發掃描與多輪量測均由 Linux VM 內的 supervisor 容器執行。

該容器使用 Ubuntu 26.04 與 Docker CLI,透過掛載的 docker.sock 控制受測容器,負責逐項執行測試、處理重試與收集結果。macOS 宿主僅負責最終結果彙整,不直接參與逐項測試的調度。

各測試組採用不同的請求數量與重複次數:

測試項目 量測方式
反向代理定點 100 併發,500,000 個請求,單次量測
高併發掃描 每個併發點 20,000 個請求,單次量測
靜態檔案與 Zstd 兩輪量測,取中位數
存取日誌開銷 兩輪量測,取中位數
HTTP/3 Pingclair、Caddy 各兩輪;nginx 四輪,取中位數

有效性判定

反向代理定點、靜態檔案、壓縮及日誌開銷測試,僅採納全部請求成功的量測結果。出現請求失敗的樣本不納入這些組別的吞吐量比較。

高併發掃描則保留失敗樣本作為診斷資料,並在結果旁明確標示錯誤率。這些數值不得直接視為全部請求成功時的有效吞吐量。

HTTP/3 組另行記錄連線層失敗。表中列出的吞吐量保留實際觀察到的連線失敗影響,不將其視為完全零錯誤的量測。

測試期間的修正

初次測試發現,nginx 預設的 keepalive_requests 1000 在高併發情境下造成連線提前關閉,影響結果。

因此,nginx 的相關設定統一調整為:

keepalive_requests 1000000;

完成調整後,重新執行整批 nginx 測試。本頁不引用調整前的數據。

本組使用四個 Node.js 後端,以 round-robin 分配請求,並維持上游持久連線重用。

定點吞吐量

測試條件為 100 併發、總計 500,000 個請求。所有列出的結果均為零錯誤。

單位:req/s。

伺服器 req/s
nginx 1.31.6 84,133
Pingclair main 78,348
Pingclair v0.2.2 77,545
Traefik v3.7.14 30,315

nginx 在此工作負載下取得最高吞吐量。

Pingclair main 達到 nginx 約 93.1% 的吞吐量,相較 v0.2.2 提升約 1.0%。與 Traefik 相比,Pingclair main 的吞吐量約為其 2.58 倍。

上述差距僅適用於本組後端、連線配置及 CPU 限制,不代表各伺服器在所有反向代理情境下的相對效能。

高併發掃描

以下為四個代表性併發點。數值單位為 req/s,括號內為請求錯誤率;未標示錯誤率者代表該次量測零錯誤。

併發數 nginx Pingclair main Pingclair v0.2.2 Traefik
101 69,201 71,227 70,603 30,028
1,001 22,182 (1.8%) 26,958 31,411 10,272
5,001 6,364 (61%) 5,908 (40%) 9,010 2,906 (12%)
9,901 2,189 (62%) 1,606 (69%) 4,880 325 (85%)

在約 100 併發時,nginx 與兩版 Pingclair 的掃描吞吐量均接近 70,000 req/s,Traefik 則約為 30,000 req/s。

隨著併發數提高,各伺服器的吞吐量均明顯下降,部分實作也開始出現大量連線或請求失敗。這些結果受到 2 CPU 容器配額、8 GB VM 容量,以及負載產生器本身的資源使用共同影響,不能單獨歸因於伺服器實作。

值得注意的是,Pingclair v0.2.2 是本次掃描中唯一在 9,901 併發下仍維持零錯誤的受測版本。

相較之下,main 在 5,001 與 9,901 併發時的錯誤率分別達到 40% 與 69%。新版在一般負載下的吞吐量略有提升,但極端高併發情境下的穩定性明顯不如 v0.2.2。

2026-10-12 複查

針對上述差異,重新執行 main 與 v0.2.2 在 5,001 及 9,901 併發下的測試,每列仍為 20,000 個請求。

複查結果如下:

併發數 main 錯誤率 v0.2.2 錯誤率
5,001 44% 0%
9,901 59% 0%

main 的失敗均發生於連線層,未觀察到 HTTP 5xx 回應。

v0.2.2 在兩個併發點均完成全部 20,000 個請求,且沒有錯誤。

複查結果再次呈現相同的版本差異,顯示此現象並非首次掃描獨有。其根本原因尚未確認,後續將針對連線處理、資源限制及相關版本變更進行調查。

本組測試比較不同檔案大小及編碼方式下的服務吞吐量。

226 B 與 10 KiB 檔案每輪發出 500,000 個請求,2 MiB 檔案每輪發出 5,000 個請求。各列均採用兩輪量測的中位數,且沒有請求失敗。

單位:req/s。

檔案與編碼 Pingclair main Pingclair v0.2.2 nginx 1.31.6 Caddy 2.11.7
226 B(身分編碼) 181,429 177,053 35,046 18,057
10 KiB(身分編碼) 129,790 124,398 31,825 15,547
10 KiB + Zstd 127,721 127,286 21,666 11,037
2 MiB(身分編碼) 1,441 1,459 1,102 635
2 MiB + Zstd 1,884 2,201 437 280

Pingclair 在本組所有靜態檔案測試中均取得最高或接近最高的吞吐量。

以 main 為例:

  • 226 B 身分編碼: 吞吐量約為 nginx 的 5.18 倍、Caddy 的 10.05 倍。
  • 10 KiB 身分編碼: 約為 nginx 的 4.08 倍、Caddy 的 8.35 倍。
  • 10 KiB + Zstd: 約為 nginx 的 5.90 倍、Caddy 的 11.57 倍。
  • 2 MiB + Zstd: 約為 nginx 的 4.31 倍、Caddy 的 6.73 倍。

動態 Zstd 壓縮是本次測試中差距較為顯著的工作負載之一。不過,效能差距並非固定倍率,而是隨檔案大小、壓縮設定與實際傳輸資料量而變化。

在 2 MiB + Zstd 測試中,v0.2.2 達到 2,201 req/s,高於 main 的 1,884 req/s,差距約 14.4%。這與較小檔案的測試趨勢不同,值得進一步分析。

這些結果衡量的是完整 HTTP 回應的處理能力,包含編碼、傳輸及伺服器開銷,而非單純的 Zstd 壓縮速度。

Traefik 不提供原生靜態檔案託管功能,因此未納入本組比較。

🧾 存取日誌開銷(Telemetry Tax)

Section titled “🧾 存取日誌開銷(Telemetry Tax)”

存取日誌有助於問題診斷與流量觀測,但記錄、格式化及寫入日誌也會消耗運算資源。

本組以 226 B 靜態檔案為工作負載,比較停用存取日誌(A)與啟用 JSON 存取日誌(B)的吞吐量差異。

日誌寫入位於記憶體中的 tmpfs,藉此減少持久化儲存裝置的影響。

以下為兩輪量測的中位數,單位為 req/s。

伺服器 A:無日誌 B:JSON 日誌 吞吐量保留率
Pingclair main 176,379 162,103 92%
Pingclair v0.2.2 176,273 155,769 88%
nginx 1.31.6 37,256 35,095 94%

吞吐量保留率定義為:

保留率 = 啟用日誌後的吞吐量 ÷ 停用日誌時的吞吐量

結果顯示,nginx 的相對日誌開銷最低,啟用 JSON 日誌後仍保留約 94% 的吞吐量。

Pingclair main 的保留率約為 91.9%,高於 v0.2.2 的 88.4%,提升約 3.5 個百分點。

換言之,main 的日誌開銷由舊版約 11.6% 降至 8.1%,顯示新版在這項工作負載下的日誌處理效率有所改善。

就絕對吞吐量而言,Pingclair main 啟用 JSON 日誌後仍達到 162,103 req/s,約為 nginx 的 4.62 倍。

需要注意的是,本組使用 tmpfs 作為日誌儲存位置,並未衡量持久化磁碟、遠端日誌收集或高負載日誌輪替的額外成本。

Caddy 未納入本組比較。

本組測試使用 226 B 靜態檔案,觀察 HTTP/3 在頻繁建立與關閉 QUIC 連線時的吞吐量。

每輪量測持續 10 秒,並採用多輪結果的中位數。Pingclair 與 Caddy 各執行兩輪;由於 nginx 的輪間變異較大,額外增加至四輪。

單位:req/s。

伺服器 req/s
Pingclair main 2,338
Pingclair v0.2.2 2,322
nginx 1.31.6 1,857
Caddy 2.11.7 1,400

兩版 Pingclair 的 HTTP/3 吞吐量相近,差距低於 1%。

在本組測試條件下,Pingclair main 的吞吐量約為 nginx 的 1.26 倍、Caddy 的 1.67 倍。

所有已完成的 HTTP 請求均成功。nginx 在部分測試輪次中出現少量連線層失敗,最高約占連線數的 2%;表列結果保留了這些失敗對實際吞吐量的影響。

工作負載說明

本組採用每條 QUIC 連線完成一個請求後立即重新建立連線的模式。

因此,測試結果主要反映 QUIC 連線建立、TLS 握手、連線關閉及 HTTP/3 請求處理的綜合成本,並不代表長時間重用同一條 QUIC 連線時的持續吞吐能力。

tquic_client 的 --total-requests-per-thread 0 是本組量測的必要參數。在使用的版本中,若省略此參數,客戶端會在首個請求完成後結束執行,無法形成預期的 10 秒測試視窗。

加入該參數後,-d 10 才能控制完整的量測時間。

HTTP/3 組仍屬實驗性測試。其絕對吞吐量受到負載產生器、QUIC 實作,以及 OrbStack 容器網路 UDP 行為的共同影響,應僅在本次環境與工作負載範圍內比較。

容器與虛擬化環境

所有測試均在搭載 Apple M2、16 GB 記憶體的 MacBook Pro 上,透過 OrbStack Linux VM 執行。

測得的吞吐量不代表原生 Linux、FreeBSD、macOS 或其他硬體平台上的絕對效能,亦不構成生產環境的容量保證。

CPU 配額與並行模型

每個受測伺服器容器限制使用 2 顆 CPU,但保留各軟體預設的 worker 與執行緒配置。

由於執行緒模型、排程策略及資源管理方式不同,在其他 CPU 配額或硬體環境下,相對效能排名可能改變。

高併發掃描

掃描每個併發點僅發出 20,000 個請求,且只執行一次。

在數千併發的情境下,請求數量相對於連線數偏少,結果更適合用於觀察極端連線壓力下的行為,而非估計長時間穩態吞吐量。

連線失敗也可能涉及負載產生器、容器網路或作業系統的資源限制,不能僅憑錯誤率判定伺服器的根本問題。

壓縮設定

各伺服器使用自身的 Zstd 實作及指定壓縮設定。

由於壓縮策略及輸出資料量可能不同,Zstd 測試結果應理解為完整服務路徑的效能比較,而非相同壓縮工作量下的演算法效能排名。

HTTP/3 工作負載

HTTP/3 測試使用短生命週期的 QUIC 連線,不能代表長連線、多路複用或真實網際網路環境下的所有 HTTP/3 使用情境。

本次測試亦未涵蓋不同封包遺失率、網路往返延遲或頻寬限制下的表現。

未參與比較的項目

Caddy 未納入反向代理與日誌開銷組。

Traefik 不具備原生靜態檔案託管功能,因此未納入靜態檔案測試;本次亦未量測 Traefik 的 HTTP/3 表現。

缺席的項目不代表其效能高低。

版本與結果快照

本頁記錄的是 2026 年 10 月 11 日至 12 日期間取得的量測結果,涵蓋當時的正式發行版本及特定開發提交。

後續版本即使修正相關問題,也不會追溯改變本次測試數據。新的效能結論須以重新執行的量測為準。

Pingclair 儲存庫提供基準測試的通用方法、有效性判定規則及相關測試工具;本次量測的完整方法(環境、候選版本、容器配置與命令)記錄於:

本頁列出的數值均為指定版本、測試環境與工作負載下的量測結果。比較應以相同測試條件為前提,不宜將不同平台、不同版本或不同負載下的結果直接合併解讀。