[Note] Varnish 3.x 與 VMOD header 模組

其實好一陣子沒有碰 Varnish 這個東西,然後剛好有人說有快取問題,就拿起來重新看了一下。然後才發現,欸,已經出到 3.x 了耶!而且 Varnish Cache 也有把專案搬到 GitHub 上面去維護了說。

雖然我在 Ubuntu 裝的是 3.0.2,然後去 GitHub 上面抓 libvmod-header,永遠都編不過。

最後發現他有更新,只支援 3.0.3(崩潰

什麼是 Varnish

不解釋。

快取作用的基本狀況

以前其實在做這一塊的時候,並沒有特別會去注意關於 Cookie 這件事情。因為,我根本就不太會用到 Cookie 嘛,而且,這年頭誰還在用 Cookie 啊(喂!所以說,當時也就沒有很在意到底變動的區塊是否會被 Cache 這件事情。

想說,反正,即時變動的區域我本來就要更新,沒有被快取或是沒有命中也是很合理地(欸

結果這次的問題是 SSO 的問題!請不要問我什麼叫做 SSO,謝謝。在反覆測試的情況下,Varnish 對於快取是否運作的重點在,

  • 當畫面有 Cookie 或是 HTTP header 告訴他過期的時候
  • 當客戶端告訴他,我要強迫更新取得新版的時候
  • 第一次進來的客戶,會從伺服器取得一份新的畫面
  • 當伺服器端告訴 Varnish 有 Cookie 的時候(在 PHP 中叫做 setcookie

通常,遇到 Cookie 的地方,一般來說我們會用 vcl_hash 去把它解掉,讓他一旦有使用 Cookie 的時候,我們就使用 hash_data(req.http.Cookie) 去把這份資料,加入頁面的 Hash 裡面,讓他去產生快取。

好,這沒有問題(蓋章

鬼打牆

請注意上一個地方的最後一點,就是當伺服器告訴 Varnish 說,欸,我要設定一個 Cookie 喔!然後,Varnish 就永遠不會生效,換句話說,只要伺服器端對使用者作出 setcookie 這個動作的時候,Varnish 就認為這個畫面無法被快取。

是,Varnish 確實會因為 Cookie 的關係,把快取的邏輯設定為 hit_for_pass,然而,這次的鬼打牆則是在,當你的回應當中,也就是 resp.http.Set-Cookie 不等於空值,或是 beresp.http.Set-Cookie 不等於空值的情況下,Varnish 會把這樣的狀況全部都 hit_for_pass,也就是讓 beresp.ttl 永遠都小於 0 的狀況。來告訴使用者或是伺服器,我這個頁面我不快取了,因為他必須要在下一次的動作中被更新。

所以,當你的程式中有對 Cookie 做操作,你的 Varnish 就會不理你。

也許你會說,那市面上那麼多人都說,在 vcl_recv 裡面,對 req.http.Cookie 做判斷,或是在 vcl_fetch 中,對 beresp.http.Set-Cookie 做清除呢?

嗯,你會把一狗票要用的 Cookie 一起清掉喔(啾咪

libvmod-header 模組

不解釋。

import header;

sub vcl_fetch {
    header.remove(beresp.http.Set-Cookie, "(?!(=deleted))");
}

打完收工(喂

結語

對於 Varnish 針對 Cookie 做快取回避的動作上來看,這是很合理的一件事情。當然也有人對 Hash 不安全這件事情有點意見啦。不過,我還是覺得,只是快取而已,我想應該不會有人會把後台也快取吧。

Varnish 模組越來越多元,看來不止可以單純當作 Cache 的服務,似乎還可以做更多壞事啊(欸

Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei