簡單一招竟把nginx服務器性能提升50倍

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

一、需求背景




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

架構流程大致如下所示:

數據更新後會重新生成新一輪次的文件,刷新 CDN 的時候會觸發大量回源請求,應用服務器極端情況得 hold 住這 9w 的 QPS。

一、第一次壓測




雙機房一共 40 臺 4C 的機器,25KB 數據文件,5w 的 QPS 直接把 CPU 打到 90%。

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

就在這時測試同學反饋壓測的數據不對,最後一輪文件最大會有 125KB,雪上加霜。

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

到底是哪裏在消耗 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 作爲家喻戶曉的 web 服務器,以高性能高併發著稱,區區一個靜態數據文件就把應用服務器壓的這麼高,一定是哪裏不對。

三、第三次壓測




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

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

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

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

•動態壓縮

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

這個模塊是默認編譯的,詳情可以查看 https://nginx.org/en/docs/http/ngx_http_gzip_module.html

•靜態壓縮

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

這個模塊需要單獨編譯,詳情可以查看 https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html

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

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

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

gzip_static on;

面對 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    -

本文分享自微信公衆號 - 京東雲開發者(JDT_Developers)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章