簡單一招竟把nginx伺服器效能提升50倍

張哥說技術發表於2024-02-07

來源:京東雲開發者

本文記錄了一次基於實際業務場景的nginx調優過程,透過一步步的分析實踐把伺服器整體效能提升了50倍。

一、需求背景




接到重點業務需求要分輪次展示資料,預估最高承接 9w 的 QPS,作為後端工程師下意識的就是把介面寫好,分級快取、機器擴容、執行緒拉滿等等一系列連招準備,再因為資料更新頻次兩隻手都數得過來,我們採取了最穩妥的處理方式,直接生成靜態檔案拿 CDN 抗量。

架構流程大致如下所示:

簡單一招竟把nginx伺服器效能提升50倍

資料更新後會重新生成新一輪次的檔案,重新整理 CDN 的時候會觸發大量回源請求,應用伺服器極端情況得 hold 住這 9w 的 QPS。

一、第一次壓測




雙機房一共 40 臺 4C 的機器,25KB 資料檔案,5w 的 QPS 直接把 CPU 打到 90%。

這明顯不符合業務需求啊,咋辦?先無腦加機器試試唄。

就在這時測試同學反饋壓測的資料不對,最後一輪檔案最大會有 125KB,雪上加霜。

於是乎檔案替換,機器數量整體翻一倍擴到 80 臺,服務端 CPU 依然是瓶頸,QPS 加不上去了。

簡單一招竟把nginx伺服器效能提升50倍

到底是哪裡在消耗 CPU 資源呢,整體架構已經簡單到不能再簡單了。

這時候我們注意到為了節省網路頻寬 nginx 開啟了 gzip 壓縮,是不是這小子搞的鬼。

















server{      listen 80;            gzip on;      gzip_disable "msie6";      gzip_vary on;      gzip_proxied any;      gzip_comp_level 6;      gzip_buffers 16 8k;      gzip_http_version 1.1;      gzip_types text/plain application/css text/css application/xml text/javascript application/javascript application/x-javascript;
......}
二、第二次壓測




為了驗證這個猜想,我們把 nginx 中的 gzip 壓縮率從 6 調成 2,以減少 CPU 的計算量。

gzip_comp_level 2;

這輪壓下來 CPU 還是很快被打滿,但 QPS 勉強能達到 9w,坐實了確實是 gzip 在耗 CPU。

簡單一招竟把nginx伺服器效能提升50倍

nginx 作為家喻戶曉的 web 伺服器,以高效能高併發著稱,區區一個靜態資料檔案就把應用伺服器壓的這麼高,一定是哪裡不對。

三、第三次壓測




明確了 gzip 在耗 CPU 之後我們潛下心來查閱了相關資料,發現了一絲進展。

html/css/js 等靜態檔案通常包含大量空格、標籤等重複字元,重複出現的部分使用「距離加長度」表達可以減少字元數,進而大幅降低頻寬,這就是 gzip 無失真壓縮的基本原理。

作為一種端到端的壓縮技術,gzip 約定檔案在服務端壓縮完成,傳輸中保持不變,直到抵達客戶端。這不妥妥的理論依據嘛~

nginx 中的 gzip 壓縮分為動態壓縮和靜態壓縮兩種:

•動態壓縮

伺服器給客戶端返回響應時,消耗自身的資源進行實時壓縮,保證客戶端拿到 gzip 格式的檔案。

這個模組是預設編譯的,詳情可以檢視

•靜態壓縮

直接將預先壓縮過的 .gz 檔案返回給客戶端,不再實時壓縮檔案,如果找不到 .gz 檔案,會使用對應的原始檔案。

這個模組需要單獨編譯,詳情可以檢視

如果開啟了 gzip_static always,而且客戶端不支援 gzip,還可以在服務端加裝 gunzip 來幫助客戶端解壓,這裡我們就不需要了。

查了一下 jdos 自帶的 nginx 已經編譯了 ngx_http_gzip_static_module,省去了重新編譯的麻煩事。

簡單一招竟把nginx伺服器效能提升50倍

接下來透過 GZIPOutputStream 在本地額外生成一個 .gz 的檔案,nginx 配置上靜態壓縮再來一次。

gzip_static on;

簡單一招竟把nginx伺服器效能提升50倍

面對 9w 的QPS,40 臺機器只用了 7% 的 CPU 使用率完美扛下。

為了探底繼續加壓,應用伺服器 CPU 增長緩慢,直到網路流出速率被拉到了 89MB/s,擔心影響宿主機其他容器停止壓力,此時 QPS 已經來到 27w。

qps 5w->27w 提升 5 倍,CPU 90%->7% 降低 10 倍,整體效能翻了 50 倍不止,這回舒服了~

四、寫在最後




經過一連串的分析實踐,似乎靜態壓縮存在“壓倒性”優勢,那什麼場景適合動態壓縮,什麼場景適合靜態壓縮呢?一番探討後得出以下結論:

純靜態不會變化的檔案適合靜態壓縮,提前使用gzip壓縮好避免CPU和頻寬的浪費。動態壓縮適合API介面返回給前端資料這種動態的場景,資料會發生變化,這時候就需要nginx根據返回內容動態壓縮,以節省伺服器頻寬。

作為一名後端工程師,nginx 是我們的老相識了,抬頭不見低頭見。日常工作中配一配轉發規則,查一查 header 設定,基本都是把 nginx 作為反向代理使用。這次是直接訪問靜態資源,調整過程的一系列最佳化加深了我們對 gzip 的動態壓縮和靜態壓縮的基本認識,這在 NG 老炮兒眼裡顯得微不足道,但對於我們來說卻是一次難得的技能擴充機會。

在之前的職業生涯裡,我們一直聚焦於業務架構設計與開發,對效能的最佳化似乎已經形成思維慣性。面對大資料量長事務請求,減少迴圈變批次,增大併發,增加快取,實在不行走非同步任務解決,一般瓶頸都出現在 I/O 層面,畢竟磁碟慢嘛,減少與資料庫的互動次數往往就有效果,其他大機率不是問題。這回有點兒不一樣,CPU 被打起來的原因就是出現了大量資料計算,在高併發請求前,任何一個環節都可能產生效能問題。

-    END    -

來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024923/viewspace-3006579/,如需轉載,請註明出處,否則將追究法律責任。

相關文章