使用 NGINX 進行微程式快取的好處

OneAPM官方技術部落格發表於2016-05-17

【編者按】本文作者為 Owen Garrett,主要介紹使用 nginx 進行微程式快取的好處,輔之以生動的例項。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。

NGINXNGINX Plus 被廣泛應用於網站內容快取,小到個人網站,大到一些世界大型內容分發網站(CDNs),例如 MaxCDN 和 CloudFlare。

微程式快取通過將動態、非個人化的內容快取很短的時間,能有效加速這些內容的傳遞。在本文中,筆者將展示如何利用微程式快取技術將一個基於 WordPress 的應用程式最高提速400倍。

為什麼要快取內容?

快取能夠一舉兩得:通過更快地傳遞內容,快取可以改善網站效能,同時減輕源伺服器的負擔。快取的效率取決於內容的快取度。這些內容可以儲存多長時間,如何檢查更新,相同的快取內容可以發給多少使用者?

使用 NGINX 進行微程式快取的好處

快取靜態內容,例如圖片、JavaScript 和 CSS 檔案和幾乎不變的網頁內容是個相當簡單的過程。快取更新的處理方法包括常規暫停條件 Get,如果有必要,還可以用cache-busting技術來替換引用物件的URL。

快取個人化內容(即通過伺服器應用為每位使用者定製的內容)幾乎不可能,因為伺服器對同一資源的每次請求的回覆都不相同。伺服器端引用(SSI)和頁面片段快取(ESI)等技術可以協助組合網頁,但是這些技術很難實行,而且不一定能改善效能。

兩者中間是個有趣的待快取物件:可能會無計劃更換,但是並非針對每位使用者(或者在客戶端通過 JavaScript實現個性化)的動態內容。這類內容的生成代價很高,提供過時版本又會帶來新的問題。

適合快取的動態內容包括:

  • 經常更新的新聞或部落格網站的首頁,每隔幾秒就有新文章釋出
  • 最近資訊 RSS
  • 持續整合(CI)或搭建平臺的進度頁面
  • 庫存、進度或籌款計數
  • 彩票開獎結果
  • 日曆資料
  • 在客戶端呈現的個人化動態內容,例如利用 cookie 資料展示的廣告內容或資料(“你好,你的名字”)

動態內容的微程式快取

微程式快取是一種快取技術,將內容快取1秒左右很短的時間。這意味著網站更新會延遲不到1秒鐘,這在很多情況下是可以接受的。

這種短暫快取能給網站效能帶來可察覺的改觀嗎?來試試看!

測試應用程式

在本次測試中,筆者用的是標準 WordPress 設定,並填充了一些樣本內容

使用 NGINX 進行微程式快取的好處

顯然,即便是處理基本內容,WordPress 伺服器也存在效能問題:以 ab 為基準時,它一秒鐘只能服務5.53個請求:

root@nginx-client:~## ab -c 10 -t 30 -k http://nginx-server/
Requests per second:    5.53 [#/sec] (mean)
Time per request:       1809.260 [ms] (mean)
Time per request:       180.926 [ms] (mean, across all concurrent requests)
Transfer rate:          319.74 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       3
Processing:  1430 1735 259.4   1580    2228
Waiting:      537  683 119.7    624     980
Total:       1430 1735 259.4   1580    2228

測試中,vmstat 顯示造成瓶頸的原因是利用 PHP 生成頁面的 CPU 消耗(在 cpu 範圍的 us 一列,數值為96到98。)

root@nginx-server:/var/www/html## vmstat 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
10  0      0 136076  44944 585920    0    0     0     0  476 1665 96  4  0  0  0
10  0      0 140112  44952 585924    0    0     0     4  506 1773 98  2  0  0  0
10  0      0 136208  44952 585924    0    0     0     0  576 2057 97  3  0  0  0

熱門使用量顯示,CPU 被10個執行 PHP 直譯器的 Apache httpd 程式佔用。

這種設定本身就是問題——它限制了網站每秒鐘處理請求的數量不能超過5個,很容易遭到 DOS攻擊,而通過新增 CPU 來解決這個問題意味著每年的託管費用都要增加1000美元。

利用 NGINX 簡化微程式快取

利用 NGINX 來加速服務只需兩步。

第一步: 通過 NGINX 代理伺服器

在 WordPress 伺服器安裝 NGINX 或 NGINX Plus 並進行配置,讓它接收訪問流量並在內部轉發到 WordPress 伺服器:

使用 NGINX 進行微程式快取的好處

NGINX 代理伺服器配置比較簡單:

server {
    listen external-ip:80;  # External IP address

    location / {
        proxy_http_version 1.1; # Always upgrade to HTTP/1.1
        proxy_set_header Connection ""; # Enable keepalives
        proxy_set_header Accept-Encoding ""; # Optimize encoding
        proxy_pass http://wordpress-upstreams;
    }

    status_zone wordpress; # NGINX Plus status monitoring
}

upstream wordpress-upstreams {
    zone wordpress 128k;
    keepalive 20; # Keepalive pool to upstream

    server localhost:80;
}

筆者還修改了 Apache 配置(監聽埠號和虛擬伺服器),這樣 Apache 就繫結到了 localhost:80。

你可能以為新增額外的代理伺服器會對效能造成負面影響,但是實際上效能變化可以忽略不計:

root@nginx-client:~# ab -c 10 -t 30 -k http://nginx-server/
Requests per second:    5.63 [#/sec] (mean)
Time per request:       1774.708 [ms] (mean)
Time per request:       177.471 [ms] (mean, across all concurrent requests)
Transfer rate:          324.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       1
Processing:  1423 1709 341.3   1532    2794
Waiting:      554  703 165.0    608    1165
Total:       1423 1709 341.4   1532    2794

在更繁忙的伺服器(處理更多併發請求)中,僅靠 NGINX 實現的優化就能帶來顯著的效能提升

第二步: 啟動短期快取

在伺服器配置中只新增了兩條指令,NGINX 或 NGINX Plus 就可以快取所有可快取的響應。帶有 200 OK 狀態碼的響應只快取1秒鐘。

proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;

server {
    proxy_cache cache;
    proxy_cache_valid 200 1s;
    ...
}

筆者再次執行基準測試時,看到了效能顯著提升:

root@nginx-client:~# ab -c 10 -t 30 -k http://nginx-server/
Complete requests:      18022
Requests per second:    600.73 [#/sec] (mean)
Time per request:       16.646 [ms] (mean)
Time per request:       1.665 [ms] (mean, across all concurrent requests)
Transfer rate:          33374.96 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.5      1      10
Processing:     0   16 141.5      3    2119
Waiting:        0    6  54.6      1     818
Total:          1   17 141.5      4    2121

這是120倍的效能優化,從每秒鐘處理5條請求到600條;這聽起來太棒了,不過還有個問題。

快取進展順利,筆者驗證了內容的確是每秒更新的(因此永不過時),但是未曾預料到的情況發生了。你會發現處理時間的標準偏差很大(141.5毫秒)。CPU 使用率還是100%(用 vmstat 測量),熱門使用量顯示有10個活躍的 httpd 程式。

筆者還從 NGINX Plus 的活動檢測控制皮膚找到進一步的線索。測試前:

使用 NGINX 進行微程式快取的好處

測試後:

使用 NGINX 進行微程式快取的好處

控制皮膚報告顯示,NGINX 在測試期間處理了18032條請求(ab 彙報的18022條請求,以及基準在30秒結束時突出的10條請求)。但是,NGINX 轉發了150條請求到上游伺服器,在快取內容1秒鐘的情況下,這比我們期望的30秒測試應有的請求數多得多。

怎麼回事?為什麼 CPU 使用率很高,快取更新比預期數字更大?

這是因為每次快取條目過期時,NGINX 就會停止使用它。NGINX 將所有請求都轉發給上游 WordPress 伺服器,直到它收到響應,可以用新內容來快取。

這導致了 WordPress 伺服器收到的請求經常激增到10條。這些請求會佔用 CPU,比快取響應的請求延遲更多,這就解釋了測試結果中的高標準差。

用 NGINX 優化微程式快取

筆者想要的策略很清晰:需要在確保快取內容最新的情況下,儘可能少地向上遊源伺服器轉發請求。在快取內容不斷更新的前提下,筆者願意從快取獲取舊的(延後1到2秒)響應。要實現這一目標,需要新增兩條指令:

  • proxy_cache_lock ——限制填充快取的併發嘗試數量,這樣當一條快取入口被建立後,對該資源的請求將會在 NGINX 中排隊。
  • proxy_cache_use_stale ——配置 NGINX,使它提供舊的(最近快取的)內容,同時更新快取入口。

加上之前已經新增的快取指令,筆者得到如下伺服器配置:

server {
    proxy_cache one;
    proxy_cache_lock on;
    proxy_cache_valid 200 1s;
    proxy_cache_use_stale updating;
    ...
}

基準測試結果的變化十分驚人。每秒鐘的請求數量從600跳躍到接近2200:

root@nginx-client:~# ab -c 10 -t 30 -n 100000 -k http://nginx-server/
Concurrency Level:      10
Time taken for tests:   30.001 seconds
Complete requests:      65553
Failed requests:        0
Keep-Alive requests:    0
Total transferred:      3728905623 bytes
HTML transferred:       3712974057 bytes
Requests per second:    2185.03 [#/sec] (mean)
Time per request:       4.577 [ms] (mean)
Time per request:       0.458 [ms] (mean, across all concurrent requests)
Transfer rate:          121379.72 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.3      1       5
Processing:     1    4   8.1      3     661
Waiting:        0    1   2.6      1     250
Total:          1    5   8.1      4     661

CPU 使用率也低多了(注意 cpu 下面 id 一欄的空閒時間):

root@nginx-server:/var/www/html# vmstat 3
procs -----------memory---------- ---swap-- -----io---- -system--- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs  us sy id wa st
 1  0      0 106512  53192 641116    0    0     0    37 11016 3727 19 45 36  0  0
 1  0      0 105832  53192 641808    0    0     0    68 17116 3521 13 56 31  0  0
 1  0      0 104624  53192 643132    0    0     0    64 14120 4487 15 51 33  0  0

資料傳輸率(121379.72千位元組/秒,或121兆位元組每秒)相當於0.97千兆,因此該測試受網路限制。CPU 平均使用率為66%,該伺服器的峰值效能應該大概為2185/0.66 = 3300 個請求/秒。

使用 NGINX 進行微程式快取的好處

另外,關注 ab 報告的連續響應時間(標準偏差只有8.1毫秒),以及操作皮膚顯示的30秒測試中轉發給上游伺服器的請求數量很少(16):

使用 NGINX 進行微程式快取的好處

為什麼只有16條請求?我們知道快取到1秒鐘時會清零,這個更新過程最多需要0.661秒(從 ab 結果來看),因此可以推測,更新頻率不會快於每1.66秒一次。在30秒鐘的時間之外,只會收到最多18(30/1.66)條請求。

瞭解更多

本文簡單展示了在短時間內快取動態內容可能帶來的好處,以及 NGINX Plus 的活動監測資料在調整和診斷快取配置時的用處。如果你想在生產環境中使用微程式快取,筆者建議你建立並測試一個更為複雜的快取規則,針對更長時間內的微程式快取動態和靜態內容。

NGINX Plus 還有一項快取清除功能,可以用來迅速清除 NGINX 快取中的特定內容。如果你想快取更長時間的內容,可以將該功能編入程式,但是一旦你更改原始內容,就要立即更新該程式。

要想了解更多資訊,請查閱以下資源:

本文系 OneAPM 工程師編譯呈現。OneAPM Browser Insight 是一個基於真實使用者的 Web 前端效能監控平臺,能夠幫大家定位網站效能瓶頸,網站加速效果視覺化;支援瀏覽器、微信、App 瀏覽 HTML 和 HTML5 頁面。想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格

本文轉自 OneAPM 官方部落格

原文地址: https://www.nginx.com/blog/benefits-of-microcaching-nginx/

相關文章