Varnish3.0中文入門教程-應用篇

第二部分:應用篇
當我們部署好之後,自然就是要學習怎麼使用,Linux下,尤其是Server的Linux怎麼可能有GUI呢。所以,學習配置文件的語法和控制檯就很關鍵了。
下面是要的學習內容目錄,我們還是依次進行。

  1. Backend servers

  2. Starting Varnish

  3. Logging in Varnish

  4. Sizing your cache

  5. Put Varnish on port 80

  6. Varnish Configuration Language – VCL

  7. Statistics

  8. Achieving a high hitrate

  9. Cookies

  10. Vary

  11. Pitfall – Vary: User-Agent

  12. Purging and banning

  13. Edge Side Includes

  14. Running inside a virtual machine (VM)

  15. Advanced Backend configuration

  16. Directors

  17. Health checks

  18. Misbehaving servers

  19. Advanced topics

  20. Troubleshooting Varnish

一、Backend servers
Varnish有後端(或稱爲源)服務器的概念。後端服務器是指Varnish提供加速服務的那臺,通常提供內容。
第一件要做的事情是告訴Varnish,哪裏能找到要加速的內容。打開varnish配置文件,源碼包安裝的在/usr/local/etc/varnish/default.vcl中,rpm安裝的在/etc/varnish/default.vcl中。
頂部有如下注釋:

1
2
3
4
# backend default {
# .host = "127.0.0.1";
# .port = "8080";
# }

我們修改下,把8080變成80

1
2
3
4
backend default {
.host = "127.0.0.1";
.port = "80";
}

這段配置,定義了一個Varnish中的一個後端(Backend),叫做default。當Varnish需要從這個後端獲得內容時,它就會連接到127.0.0.1的80端口上。
Varnish可以有多個後端,你甚至可以爲了負載均衡將幾個後端加入到一個集羣后端中。
現在我們完成了Varnish的基本配置,接下來讓我們在8080端口上把Varnish起起來,對它做些實驗性測試。
二、Starting Varnish
在開始下面的內容之前,你先要確保現在你的varnish沒有在運行,如果有,就用pkill varnishd去關閉它。然後到根目錄,輸入以下代碼:

1
# varnishd –f /usr/local/etc/varnish/default.vcl –s malloc,1G -T 127.0.0.1:2000 –a 0.0.0.0:8080

我添加了一些選項:
-f /urs/local/etc/varnish/default.vcl
-f選項指定了將使用哪個配置文件
-s malloc,1G
-s選項用於指定varnish使用何種存儲類型保存內容。這裏我使用malloc,這個代表我只使用內存存儲。如果還有其他後端,用:ref:tutorial-storage來表示。1G指定了分配多少內存——這裏是一個G。
-T 127.0.0.1:2000
Varnish含有內置文本管理界面。可以通過它對varnish進行管理,最主要你還不用停掉varnish。你可以給管理界面分配端口。確保你的管理界面沒有暴露給外界,因爲通過Varnish管理界面你可以很容易地訪問系統根目錄。我建議直接綁定在localhost上,就別遠程了。如果你的系統上有不可信任的user,就用防火牆規則只要限制界面訪問根目錄就行。
-a 0.0.0.0:8080
對於進入的HTTP請求,我指定varnish監聽8080。對於生產環境,你可能需要讓varnish監聽在80端口,這個是默認的。(關鍵看前面有沒有負載均衡)

現在我已經啓動了Varnish。用瀏覽器訪問下http://varnishServerIP:8080/。你應該會看到你的web應用的運行的。
Varnish運行後,應用的訪問速度更快主要取決於一些因素。如果你的應用爲每個session使用cookie的話(很多PHP和Java應用無論是否需要都會發送一個session cookie),或者應用使用驗證的話,這些varnish都不會緩存。現在先放一放,別考慮這些,等到Achieving a high hitrate的時候,我們再來好好談。
通過查看日誌,我們可以用來確定varnish是不是真的起作用了。
三、Logging in Varnish
在Varnish中,日誌的工作方式,是一個很好特性。Varnish將日誌記錄到共享內存片段,而不是記錄到一個普通文件中。當記錄到內存片段的最後處,會再從頭開始記,覆寫老數據。這個比記錄到文件要快的多,而且不需要磁盤空間。
另一方面,如果你沒有執行程序去將這些日誌寫到磁盤中的話,他們是會消失的。
Varnishlog是一個用來查看Varnish日誌的程序。Varnishlog提供給我們原始日誌。這裏還有其他客戶端,之後我們會介紹。
在啓動varnish的終端窗口,我們輸入varnishlog,然後按回車。
你會看到如下內容,使用”.”可以緩緩滾動:

1
2
0 CLI - Rd ping
0 CLI - Wr 200 PONG 1273698726 1.0

這是varnish主進程,檢查緩存進程,看是否一切正常。
現在在瀏覽器,重新加載頁面,顯示你的web應用。你會看到如下內容:

1
2
3
4
5
6
7
11 SessionOpen c 127.0.0.1 58912 0.0.0.0:8080
11 ReqStart c 127.0.0.1 58912 595005213
11 RxRequest c GET
11 RxURL c /
11 RxProtocol c HTTP/1.1
11 RxHeader c Host: localhost:8080
11 RxHeader c Connection: keep-alive

第一列可以是任意的數字,它代表具體的請求。數字相同,表示他們是同屬於一個HTTP事務的。第二列是日誌信息的標籤。所有的日誌條目都是用一個標籤去標記,該標籤代表何種行爲被記錄。以Rx開頭的標籤代表varnish正在接受數據,Tx代表正在發送數據。
第三列表示數據的是來自或者要發送給客戶(c),另外,還有爲b的情況,代表數據來自或要發送給後端(b)。第四列是被記錄的數據。
現在,你可以使用varnishlog去過濾下。基本的選項如下:
-b 只顯示varnish和後端服務器之間通信的記錄條。當你想優化緩存命中率的時候,非常有用。
-c 和-b類似,只是針對與客戶端的通信情況。
-i tag 只有顯示帶有特定標籤的行。”varnishlog –I SessionOpen”將只顯示新會話的情況。注意標籤是大小寫敏感的。
-I 通過正則表達式過濾數據,並顯示匹配行。”$varnishlog –c –I RxHeader –I Cookie”,將顯示所有來自客戶端的cookie頭信息。
-o 根據請求id,將記錄條目分組。
現在Varnish差不多工作正常,現在要將Varnish的端口編程80,進行調優。
四、Sizing your cache
給Varnish選擇多少內存,是個很艱鉅的問題。你需要考慮以下事情:
l 你的熱門數據集有多大。對一個門戶或者新聞站來說,這個數據集可能就只是首頁和它相關內容的大小。這裏包括的兩部分,一部分是隻首頁本身的文字圖片內容,另一部分是首頁會鏈接到的頁面或對象(比如圖片),這個很容易理解,首頁的內容是最可能被點擊的,命中率也會很高。
l 產生一個對象的花費有多大?有時候,如果從後端返回並不太消耗資源,同時你的內存又有限的話,我們應該緩存一部分圖片,而不是去緩存所有圖片。
l 使用varnishstat或其他工具監控n_lru_nuked計數器。如果你有很多LRU活動的話,那麼你的緩存正因空間限制在清除對象,此時你就要考慮增加緩存大小了。
清楚緩存任何對象都會攜帶保存在實際存儲區域之外的開銷。所以,即便你指定-s malloc,16G,varnish可能實際使用了兩倍。Varnish中每個對象的花銷大概是1k。所以,如果在你的緩存中有很多小對象的話,花銷是非常大的。
五、Put Varnish on port 80
直到現在,爲了測試,我們都把varnish運行在一個高位端口上。你應該測試你的應用,如果它工作正常,我們就要切換了,Varnish運行在80端口上,你的web服務器運行在高位端口上。
首先停止varnishd:

1
# pkill varnishd

並停止你的web服務器。修改web服務器的配置,將其綁定到8080端口上,替換掉原來的80。現在打開varnish的default.vcl並且改變default後端的端口到8080。
啓動你的web服務器並且開啓varnish:

1
# varnishd -f /usr/local/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000

注意,我們移除了-a選項。因爲,現在我們採用Varnish的默認設置即可,它會自動綁定到http的80端口上。現在每個訪問你站點的人,都會通過varnish訪問。
六、Varnish Configuration Language – VCL
Varnish有強大的配置系統。許多其他的系統使用配置指令,基本上就是開或關很多開關。Varnish使用領域專用語言(DSL)作爲Varnish配置語言,簡寫VCL。當請求到達開始執行時,Varnish會將這些配置轉換成二進制代碼。
VCL文件被分成多個子程序。不同的子程序在不同時候運行。有的在獲得請求時候運行,有的當文件從後端獲取後運行。
Varnish將在它工作的不同場景執行這些子程序。因爲是代碼,所以逐行執行並不是問題。在某些情況你在這個子程序調用一個action,然後該子程序執行結束。
如果不想在你的子程序中調用一個action,並且到達了最末尾,此時varnish會執行一些VCL的內置代碼。在default.vcl中的註釋部分,你會看到這些VCL代碼。
99%的情況,你都會要改動兩個子程序,vcl_recvvcl_fetch
vcl_recv
vcl_recv是在請求開始時調用的。完成該子程序後,請求就被接收並解析了。用於確定是否需要服務請求,怎麼服務,如果可用,使用哪個後端。
在vcl_recv中,你也可以修改請求。通常你可以修改cookie,或添加/移除請求頭信息。
注意在vcl_recv中,只可以使用請求對象req。

vcl_fetch
vcl_fetch是在文檔從後端被成功接收後調用的。通常用於調整響應頭信息,觸發ESI處理,萬一請求失敗就換個後端服務器。
在vcl_fecth中,你還可以使用請求對象req。還有個後端響應對象beresp。Beresp包含了後端的HTTP頭信息。
actions
最常用的action如下:
pass:當返回pass的時候,請求和隨後的響應都將被傳到後端服務器,或從那裏傳回。不會被緩存。pass可以在vcl_recv中被返回。
hit_for_pass:類似與pass,但是隻有vcl_fetch可以用。不像pass,hit_for_pass將在緩存中創建一個hitforpass對象。這有個副作用,就是緩存了不像緩存的東西。同時會將未緩存的請求傳到後端。在vcl_recv中這樣的邏輯不是必須的,因爲它發生在任何潛在對象隊列發生之前。
lookup:當在vcl_recv中返回lookup時,就等於你告訴varnish發送緩存中的內容,即使該請求應該是被pass的。在vcl_fetch中不能使用lookup。
pipe:pipe也可以在vcl_recv中返回。pipe縮短了客戶和後端的環路鏈接,並且varnish將只是待在哪裏,來回偏移字節。varnish不會在意來回發送的數據,所以你的日誌是不完整的。注意一個客戶會基於相同鏈接發送幾個請求,當使用HTTP 1.1時。所以在實際返回pipe之前,你需要讓varnish添加”Connection:close”的頭信息。
deliver:投遞緩存對象給客戶。經常在vcl_fetch中使用。
請求,響應和對象
在VCL中,有三種重要的數據結構。請求:來自客戶端;響應:來自後端服務器;對象:存儲在緩存中。
在VCL中你應該知道以下結構。
req:請求對象。當varnish接受了請求,req就會創建並生產。許多在vcl_recv中要做的工作都需要用到req。
beresp:後端響應對象。包含了從後端返回的對象的頭信息。vcl_fetch中,你會使用beresp對象。
obj:緩存了的對象。大多數是駐留在內存中的只讀對象。obj.ttl是可以寫的,剩下的都是隻讀的。
操作符
VCL中可用的操作符如下,稍後可以看例子:
=:賦值
==:比較
~:匹配。可使用正則表達式或ACLs
!:取反
&&:邏輯與
||:邏輯或
例1 – 操作頭信息
移除所有在web服務器的/p_w_picpaths目錄中的對象的cookie:

1
2
3
4
5
sub vcl_recv {
if(req.url ~ "^/p_w_picpaths") {
unsetreq.http.cookie;
}
}

現在,當請求傳到後端服務器時,他是不帶有cookie頭信息的。需要在意的是if語句,它根據正則表達式匹配了URL(屬於請求對象)。注意匹配操作符。如果它匹配,請求的cookie頭信息就會被刪除。
例2 – 操作beresp
這裏如果匹配某種條件,我們就重寫beresp的TTL屬性

1
2
3
4
5
6
sub vcl_fetch {
if(req.url ~ "\.(png|gif|jpg)$") {
unsetberesp.http.set-cookie;
setberesp.ttl = 1h;
}
}

例3 – ACLs
你創建了一個使用acl關鍵字的訪問控制列表。你可以使用匹配操作符去判斷客戶端的IP地址是否與一個ACL匹配。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Who is allowed to purge....
acl local{
"localhost";
"192.168.1.0"/24; /* and everyone on the localnetwork */
! "192.168.1.23"; /* except forthe dialin router */
}
sub vcl_recv {
if(req.request == "PURGE") {
if(client.ip ~ local) {
return(lookup);
}
}
}
sub vcl_hit {
if(req.request == "PURGE") {
setobj.ttl = 0s;
error 200 "Purged.";
}
}
sub vcl_miss {
if(req.request == "PURGE") {
error 404 "Not in cache.";
}
}


七、Statistics
現在你的varnish已經運行了,現在讓我們看看它是如何工作的吧。有幾個工具可以幫助你。
1、 varnishtop
varnishtop工具讀取共享內存日誌,並且顯示一個持續更新的最常見的記錄條的列表。
通過使用-I,-i,-X和-x選項進行適當過濾,可以用於顯示排名,有請求文檔、客戶端、用戶代理(瀏覽器)或其他記錄在日誌中的信息。
varnish –i rxurl將顯示客戶端請求的URL。varnishtop –i txurl 將顯示你的後端被什麼請求最多。varnishtop –i RxHeader –I Accept-Encoding將顯示最常見的客戶端發來的Accept-Encoding header。
2、 varnishhist
varnishhist工具讀取varnishd(1)共享內存日誌,並且提供不斷更新的直方圖,用以展示它們處理的最近的N個請求的分佈。N值和垂直刻度在左上角顯示。水平刻度是對數的。命中用管道符號(“|”)標記,未命中使用哈希符號(“#”)標記。
3、 varnishsizes
varnishsizes和varnishhist相似,但它會顯示對象的大小,不顯示完成請求消耗的時間。可以很直觀的告訴你,你正在處理的對象有多大。
4、 varnishstat
varnish有很多計數器。統計丟失數,命中數,存儲信息數,創建了的線程數,刪除的對象數,幾乎一切。varnishstat將轉存這些計數器。當對varnish進行調優時,這就很有用了。
這裏有一些程序可以定期獲取varnishstat,很好地繪出這些計數器的圖形。Munin是其中一個。你可以在http://munin-monitoring.org找到。在varnish的源碼中有一個munin的插件。
八、Achieving a high hitrate
現在Varnish已經運行,並且你可以通過Varnish訪問你的站點。除非你的應用是專門爲在一個web加速器後工作而寫的,否則爲了在Varnish中獲得高命中率,你可能需要在配置或應用上做一些修改。
除非varnish完全確定緩存你的數據室安全,否則varnish是不會緩存的。所以,爲了讓你明白varnish是如何確定的,並使如何緩存頁面的,我將通過一些很有用工具去引導你:
注意你需要一個工具去觀察傳輸於你和web服務器之間的HTTP頭信息。在varnish服務器上,首先是使用varnishlog和varnishtop,但有時候需要客戶端工具去搞清楚。下面就是我們用到的。
工具:varnishtop
你可以使用varnishtop確定出後端命中最多的URL。varnishtop –i txurl是必須的命令。你可以在前一節Statistics中,看到一些其他的varnishtop的例子。
工具:varnishlog
當你已經確定了最常發送給後端的URL是多少時,你可以使用varnishlog去查看完整的請求。varnishlog –c –o /foo/bar將給你來自客戶端(-c)的完整(-o)的匹配/foo/bar的請求。
對於擴展診斷頭信息,可以參看:http://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader
工具:lwp-request
lwp-request是perl的World-Wide Web library中的一部分。它是一些基本的程序,這些程序可以處理HTTP請求,並且給你結果。我通常使用兩個程序,GET和HEAD。
vg.no是第一個使用varnish的站點,站點的創建者很明白varnish。所以,讓我們看看他們的HTTP頭信息。我們對他們的首頁發一個GET請求:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
$ GET -H 'Host: www.vg.no' -Used http://vg.no/
Host: www.vg.no
User-Agent: lwp-request/5.834 libwww-perl/5.834
200 OK
Cache-Control: must-revalidate
Refresh: 600
Title: VG Nett - Forsiden - VG Nett
X-Age: 463
X-Cache: HIT
X-Rick-Would-Never: Let you down
X-VG-Jobb: http://www.finn.no/finn/job/fulltime/result?keyword=vg+multimedia Merk:HeaderNinja
X-VG-WebCache: joanie
X-VG-WebServer: leon

OK。我們來解釋一下。GET通常發送HTTP0.9請求,其缺少Host頭信息。所以我通過-H添加了一個Host頭信息。-U打印請求頭信息,-s打印響應狀態,-e打印響應頭信息,-d丟棄實際內容。我們並不關心內容,只要頭信息。
你可以發現,VG在他們的頭信息中添加了一些信息。像X-Rick-Would-Never表示了vg.no的某種奇怪的幽默。其他,像X-VG-Webcache是用來調試的。
所以,你可以檢查一個站點的特定URL是否設置了cookie,只需要:

1
GET -Used http://example.com/ |grep ^Set-Cookie

工具:實時HTTP頭信息
Firefox也有個插件。Live HTTP Headers可以顯示你發送和接受到的頭信息。你可以通過google找到“Live HTTP Header”,或者到https://addons.mozilla.org/en-US/firefox/addon/3829/可以找到。
HTTP頭信息的角色
隨着每個HTTP請求和響應變成一羣攜帶原數據的頭信息。varnish將查看這些頭信息,以確定這裏的內容是否適合緩存,以及緩存多久。
請注意,當考慮這些頭信息時候,實際上varnish只考慮真實web服務器中varnish自己的那部分。考慮的理論依據都在於你的控制。
術語surrogate origin cache沒有在IETF so RFC2616中很好的定義。所以varnish不同的工作方式可能會和你的預期不同。
讓我們看看你應該知道的重要的頭信息:
Cache-Control
Cache-Control指定了緩存如何處理內容。varnish關心max-age參數,並用它來計算對象的TTL。
“Cache-Control:nocache”是被忽略的,如果你需要,你也可以方便的增加支持。
所以,確保你發出的Cache-Control頭信息具有max-age。你可以看看Varnish軟件的聯盟服務器發出了什麼:

1
2
$ GET -Used http://www.varnish-software.com/|grep ^Cache-Control
Cache-Control: public, max-age=600

Age
varnish添加了一個Age頭信息,以指示在Varnish中該對象被保持了多久。你可以通過varnishlog像下面那樣抓出Age:

1
varnishlog -i TxHeader -I ^Age

Pragma
一個HTTP 1.0服務器可能會發送”Pragma:nocache”。Varnish忽略這種頭信息。在VCL中你可以很方便的增加對這種頭信息的支持。
在vcl_fetch中:

1
2
3
if(beresp.http.Pragma ~ "nocache") {
pass;
}

Authorization
如果varnish看到授權頭信息時,它會pass該請求。如果這不是你希望的,你可以unset這個頭信息。

Overriding the time-to-live(ttl)

有時你的後端會誤操作。根據你的安裝,在varnish中覆寫ttl會比修復你某些麻煩的後端要簡單的多。
你需要VCL去確定你想要的對象,然後你將beresp.ttl的值設置成你想設置的值。


1
2
3
4
5
sub vcl_fetch {
if(req.url ~ "^/legacy_broken_cms/") {
setberesp.ttl = 5d;
}
}

該例會爲你網站上過去的遺留物,將TTL設置爲5天。
Forcing caching for certain requests and certain responses
由於你還在使用那些麻煩的不能很好工作的後端,你可能會想再varnish中覆寫更多的內容。我們推薦你儘可能多的使用默認緩存規則。儘管強制varnish在緩存中查找一個對象很簡單,但我們還是不推薦。
Normalizing your namespace
一些站點可以通過很多主機名訪問。比如, http://www.varnish-software.com/ , http://varnish-software.com/和http://varnishsoftware.com/。這些都指向同一個站點。由於varnish不知道他們的區別,varnish會爲每個主機名的每個頁面做緩存。你可以通過在你的web服務器配置中設置跳轉或者使用VCL來緩解這個情況:

1
2
3
if(req.http.host ~ "(?i)^(www.)?varnish-?software.com") {
setreq.http.host = "varnish-software.com";
}

Ways of increasing your hitrate even more
接下來的章節,會闡述進一步提高命中率的方法,尤其在cookies的章節中。

  • Cookies

  • Vary

  • Purging and banning

  • Edge Side Includes

九、Cookies
varnish不會緩存來自後端的具有Set-Cookie頭信息的對象。同樣,如果客戶端發送了一個Cookie頭信息,varnish將繞過緩存,直接發給後端。
這可能太過保守。很多站點使用Google Analytics(GA)去分析他們的流量。GA通過設置cookie去跟蹤。這個cookie是供客戶端的JavaScript程序使用的,服務器是不需要的。
對很多web應用,它會完全忽視cookies,除非你正在訪問網站的特定部分。在vcl_recv中的下面的VCL代碼塊將忽略cookies,除非你訪問/admin/:

1
2
3
if( !( req.url ~ ^/admin/) ) {
unsetreq.http.Cookie;
}

非常簡單。然後,如果你需要做更復雜的處理,像在幾個cookie中移除其中一個,事情就麻煩了。遺憾的是,varnish沒有很好的工具去操作cookie。我們不得不使用正則表達式去做這件事情。如果你熟悉正則表達式,你就明白怎麼辦了。如果你不熟悉,我建議你找本書好好學習下,或者通過pcrepattern手冊頁面或其他的在線教程。
讓我展示給你看看,varnish軟件是用什麼的。我們使用一些GA的跟蹤cookie或其他類似工具的cookie。這些cookie都是供JavaScript使用的。varnish和其聯盟站不需要這些cookie,並且因爲varnish會因爲這些cookie不緩存頁面,所以當客戶端發送cookie時,我們將在VCL中丟棄這些非必要的cookie。
下面的VCL中,我們丟棄了所有的以“_”開頭的cookie:

1
2
3
4
//Remove has_js and Google Analytics __* cookies.
setreq.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
//Remove a ";"prefix, ifpresent.
setreq.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");

該例取自Varnish的wiki,在那裏你可以找到其他使用VCL做的例子。

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