Nginx Proxy_cache 實踐 (with Docker, Ngx-cache-purge, Etag)

最近在用Nuxt.js做一個SSR項目, 第一次做當(dāng)然是踩坑不少, 其中一個坑就是Nuxt文檔所提到的: 將nginx與生成的頁面和緩存代理一起使用, 文檔就一頁, 但實際可不只這么簡單.

至于為什么要選用Nuxt做項目, 而不是傳統(tǒng)的字符串模板引擎或者是前端渲染呢? 可以看我另一篇文章: 使用SSR優(yōu)化Vue的首屏加載速度與SEO (In writing :D)

下面就將闡述整個項目使用到的知識點

Nginx

nginx一般用于在項目中反向代理, 實現(xiàn)負載/靜態(tài)資源服務(wù)器等功能, 可以說項目必備了.

在這里, 我們將使用nginx反向代理node服務(wù)(nuxt的ssr服務(wù)), 并實現(xiàn)代理緩存(proxy_cache).

為什么要緩存呢? 實在是SSR效率太低, 訪問一個稍微復(fù)雜一點的頁面需要300ms的時間才能渲染并返回完畢, 有點隱隱擔(dān)憂.

系統(tǒng)優(yōu)化的最終方案是不調(diào)用系統(tǒng), 緩存就能達到這個目的.

Nginx in docker

如果你受夠了在機器上敲上百行命令行去初始化你的項目環(huán)境(安裝依賴等), 那么docker的好就不言而喻了.

docker鏡像中包含了整個項目甚至是操作系統(tǒng), 所以通常一個鏡像比單個軟件大很多, 為了不必要的磁盤占用, alpine就應(yīng)運而生了.

Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.

基于alpine構(gòu)建的nginx鏡像僅僅只有9M, 而基于debian構(gòu)建的卻有55M,你可以到這個頁面去獲取鏡像并查看詳情: nginx Tags - Docker Hub.

當(dāng)然alpine也不是沒有缺點, 由于精簡到極致, 所以很多命令都不能使用, 這可能會造成不太容易去編寫命令(如Dockerfile).

Proxy-cache-purge

在nginx中使用proxy-cache指令就能開啟代理緩存, 但如果想刷新緩存怎么辦? 在官方文檔中提到了這個, 但是NGINX Plus才支持....

NGINX Plus supports selective purging of cached files. This is useful if a file has been updated on the origin server but is still valid in the NGINX Plus cache (the Cache-Control:max-age is still valid and the timeout set by the inactive parameter to the proxy_cache_path directive has not expired). With the cache?purge feature of NGINX Plus, this file can easily be deleted. For more details, see Purging Content from the Cache.

僅僅需要這么幾行nginx配置

proxy_cache_path /tmp/cache keys_zone=mycache:10m levels=1:2 inactive=60s;

map $request_method $purge_method {
    PURGE 1;
    default 0;
}

server {
    listen 80;
    server_name www.example.com;

    location / {
        proxy_pass http://localhost:8002;
        proxy_cache mycache;

        proxy_cache_purge $purge_method;
    }
}

好像挺簡單, 但我們平民只有另辟蹊徑了.

百度/谷歌"proxy_cache_purge", 再在 https://hub.docker.com 搜一下"nginx cache pruge", 果然有友軍做了這個: procraft/nginx-purge.

不過他不是基于alpine做的, 那么現(xiàn)在就只有自己動手了, 其實有了參考就都好辦.

更多的說明就不寫了.

如果你想繼續(xù)研究這份Dockerfile是怎么寫的, 可以去我的github倉庫查看 nginx-docker.

如果你想直接用這個鏡像, 可以去我的dockerhub查看 bysir/nginx.


安裝好了這個擴展Module之后就可以編寫配置文件了.

由于我們并不是使用的Nginx Plus, 所以上面的配置是不生效的(這個坑我踩過).

那么該怎么寫配置呢?

在我們安裝的Module nginx-modules/ngx_cache_purge 倉庫中有說明.

一般來說這樣一個配置就夠用了.

http {
    proxy_cache_path  /tmp/cache  keys_zone=tmpcache:10m;

    server {
        location / {
            proxy_pass         http://127.0.0.1:8000;
            proxy_cache        tmpcache;
            proxy_cache_key    $uri$is_args$args;
            proxy_cache_purge  PURGE from 127.0.0.1;
        }
    }
}

如果不想限制訪問ip, 則直接這樣寫也可以: proxy_cache_purge PURGE;

如果想清除緩存, 僅僅需要這樣

# curl -X PURGE "http://yourdomain.com/*"

* 代表清除所有緩存, 詳情查閱剛剛所提文檔中的partial-keys.

自定義 proxy_cache_key

有時候$uri$is_args$args這樣的key不能滿足需求, 比如后端對于PC和Mobile有兩套界面, 是通過UA判斷的, 這時候如果在Nginx緩存就會出現(xiàn)問題.

這時候就需要自定義緩存key.
可以這樣

location / {
            set $ua "pc"
            proxy_pass         http://127.0.0.1:8000;
            proxy_cache        tmpcache;
            proxy_cache_key    $uri$is_args$args$ua;
            proxy_cache_purge  PURGE from 127.0.0.1;
}

With Nuxt.js

進入實戰(zhàn), 現(xiàn)在將編寫配置文件代理Nuxt項目.

可以參考Nuxt所寫的文檔 nginx-proxy, 建議查看英文文檔, 中文翻譯有點不準(zhǔn)確.

在各種試錯下, 終于寫出一個可以正常使用的的配置, 如下

ps: 我會盡量為每一段代碼寫上注釋, 但nginx的各個指令真的難理解, 腦子不夠用, 等以后有緣了再逐個弄清吧.

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=cache:10m max_size=10g;

server {
    listen       80;

    location / {
        add_header X-Cache-Status $upstream_cache_status; # 添加上緩存狀態(tài), 有Hit和Miss等. 
        proxy_ignore_headers Cache-Control; # (nuxt推薦寫法), 我猜是忽略瀏覽器的強制刷新發(fā)送的緩存控制頭, 讓強制刷新也不會擊穿緩存.
        proxy_cache_valid 500 1m; # 如果服務(wù)端返回500則只緩存1分鐘
        proxy_cache_valid any 30m; # 對于其他相應(yīng), 緩存30分鐘, 這些數(shù)值根據(jù)你的業(yè)務(wù)調(diào)整
        proxy_http_version 1.1;
        proxy_cache cache; # keys_zone
        proxy_cache_bypass $arg_nocache; # 使用?nocache=1這樣的請求參數(shù)跳過使用緩存
        proxy_cache_key $host$uri$is_args$args; # 緩存key, 如果是當(dāng)前nginx在服務(wù)多個域名, 則需要添加上$host, 否則可以不用$host.
        proxy_cache_purge PURGE; # usage: curl -X PURGE "http://youdomain.com/*"
        proxy_redirect off;
        proxy_cache_background_update off; # 緩存預(yù)熱, 根據(jù)你的需求而定. 
        proxy_cache_lock on; # 如果當(dāng)個請求在請求同一個key并且沒有緩存, 就會將后續(xù)的請求block, 防止緩存擊穿.
        proxy_cache_revalidate on; # 是否讓緩存重新生效. 如果開啟 當(dāng)緩存過期, 但是Etag相等的情況下, 會將這個緩存重新生效.
    }
}

對于上面的配置項, 都可以去nginx-caching-guidengx-http_proxy_module查閱.

Etag

Etag是用來做緩存驗證的, 瀏覽器在請求資源的時候如果帶上了Etag, 那么服務(wù)端端就可以根據(jù)Etag來判斷是否需要返回新的內(nèi)容給瀏覽器, 如果Etag相等, 那么服務(wù)端就會返回304告知瀏覽器當(dāng)前的資源是最新的 可以拿來使用, 而不是返回整個資源給瀏覽器, 大大節(jié)約了流量傳輸?shù)臅r間.

我當(dāng)然是期望nginx的proxy_cache是支持Etag的, 但是當(dāng)我配置好以后, 卻發(fā)現(xiàn)一直是200.

百度無果(習(xí)以為常), google上找到了一篇文章: nginx-proxy-cache-and-etag, 但也沒有很好得解決辦法.

最后只得讓服務(wù)端(也就是Nuxt)去計算Etag, 經(jīng)過試驗Nginx也能緩存命中, 就這樣吧.

如果你想做試驗, 可以在nuxt.config.js里配置關(guān)閉Etag, 這在nuxt中是默認開啟的.

module.exports = {
  render: {
    etag: false
  }
}

相關(guān)參考

都在文中啦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悴务,一起剝皮案震驚了整個濱河市形耗,隨后出現(xiàn)的幾起案子气嫁,更是在濱河造成了極大的恐慌奠滑,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煮寡,死亡現(xiàn)場離奇詭異唆鸡,居然都是意外死亡池凄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門阳藻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晰奖,“玉大人,你說我怎么就攤上這事腥泥〕┩浚” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵道川,是天一觀的道長午衰。 經(jīng)常有香客問我,道長冒萄,這世上最難降的妖魔是什么臊岸? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮尊流,結(jié)果婚禮上帅戒,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好逻住,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布钟哥。 她就那樣靜靜地躺著,像睡著了一般瞎访。 火紅的嫁衣襯著肌膚如雪腻贰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天扒秸,我揣著相機與錄音播演,去河邊找鬼。 笑死伴奥,一個胖子當(dāng)著我的面吹牛写烤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拾徙,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼洲炊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尼啡?” 一聲冷哼從身側(cè)響起选浑,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎玄叠,沒想到半個月后古徒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡读恃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年隧膘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺惫。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡疹吃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出西雀,到底是詐尸還是另有隱情萨驶,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布艇肴,位于F島的核電站腔呜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏再悼。R本人自食惡果不足惜核畴,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冲九。 院中可真熱鬧谤草,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至温学,卻和暖如春略贮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背枫浙。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留古拴,地道東北人箩帚。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像黄痪,于是被迫代替她去往敵國和親紧帕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359