Varnish
Varnish 是一款高性能且開源的反向代理伺服器和 HTTP 加速器,其采用全新的軟體體系機構,和現在的硬體體系緊密配合,與傳統的 squid 相比,varnish 具有性能更高、速度更快、管理更加友善等諸多優點,很多大型的網站都開始嘗試使用 varnish 來替換 squid,這些都促進 varnish 迅速發展起來。
挪威的最大的線上報紙 Verdens Gang(vg.no) 使用 3 台 Varnish 代替了原來的 12 台 Squid,性能比以前更好,這是 Varnish 最成功的應用案例。
一、Varnish的安裝
首先安裝 pcre 庫,pcre 庫是為相容正規表達式,如果不安裝,在安裝 varnish2.0 版本以上時,會提示找不到 pcre 庫。以下是 pcre 的安裝過程:
<code>#tar zxvf pcre.tar.gz</code>
<code>#cd pcre/ </code>
<code>#./configure --prefix=/usr/local/pcre/ </code>
<code>#make && make install</code>
安裝varnish:
<code>#tar xzvf varnish-3.0.2.tar.gz</code>
<code>#cd varnish-3.0.2</code>
<code>#export PKG_CONFIG_PATH =/usr/local/pcre/lib/pkgconfig </code>
<code>#./configure --prefix=/usr/local/varnish</code>
<code>#make </code>
<code>#make install</code>
啟動varnish:
<code>#varnishd -f /etc/varnish/default.vcl -s file,/var/varnish_cache,1G \</code>
<code> </code><code>-T 127.0.0.1:2000 -a 0.0.0.0:9082</code>
各參數含義:
<code>-f 指定 varnish 的配置檔案位置</code>
<code>-s 指定 varnish 緩存存放的方式,常用的方式有:“-s </code><code>file</code><code>,<dir_or_file>,<size>”。</code>
<code>-T address:port 設定 varnish 的 telnet 管理位址及其端口</code>
<code>-a address:port 表示 varnish 對 http 的監聽位址及其端口</code>
二、Varnish詳解
(一)關于varnish
1、varnish系統架構
varnish主要運作兩個程序:Management程序和Child程序(也叫Cache程序)。
Management程序主要實作應用新的配置、編譯VCL、監控Varnish、初始化varnish以及提供一個指令行接口等。Management程序會每隔幾秒鐘探測一下Child程序以判斷其是否正常運作,如果在指定的時長内未得到Child程序的回應,Management将會重新開機此Child程序。
child程序包含多種類型的線程,常見的如:
Acceptor線程:接收新的連接配接請求并相應;
Worker線程:child程序會為每隔回話啟動一個worker線程,是以,在高并發的場景中可能會出現數百個worker線程甚至更多;
Expiry線程:從緩存中清理過期内容;
Varnish依賴“工作區(workspace)”以降低線程在申請或修改記憶體時出現競争的可能性。在varnish内部有多種不同的工作區,其中最關鍵的當屬于管理會話資料的session工作區。
2、varnish日志
為了與系統的其它部分進行互動,Child程序使用了可以通過檔案系統接口進行通路的共享記憶體日志(shared memory log),是以,如果某線程需要記錄資訊,其僅需要持有一個鎖,而後向共享記憶體中的某記憶體區域寫入資料,再釋放持有的鎖即可。而為了減少競争,每個worker線程都使用了日志資料緩存。
共享記憶體日志大小一般為90M,其分為兩部分,前一部分為計數器,後半部分為用戶端請求的資料。varnish提供了多個不同的工具如varnishlog、varnishncsa或varnishstat等來分析共享記憶體日志中的資訊并能夠以指定的方式進行顯示。
3、VCL
Varnish Configuration Language (VCL)是varnish配置緩存政策的工具,它是一種基于“域”(domain specific)的簡單程式設計語言,它支援有限的算術運算和邏輯運算操作、允許使用正規表達式進行字元串比對、允許使用者使用set自定義變量、支援if判斷語句,也有内置的函數和變量等。使用VCL編寫的緩存政策通常儲存至.vcl檔案中,其需要編譯成二進制的格式後才能由varnish調用。事實上,整個緩存政策就是由幾個特定的子例程如vcl_recv、vcl_fetch等組成,它們分别在不同的位置(或時間)執行,如果沒有事先為某個位置自定義子例程,varnish将會執行預設的定義。
VCL政策在啟用前,會由management程序将其轉換為C代碼,而後再由gcc編譯器将C代碼編譯成二進制程式。編譯完成後,management負責将其連接配接至varnish執行個體,即child程序。正是由于編譯工作在child程序之外完成,它避免了裝載錯誤格式VCL的風險。是以,varnish修改配置的開銷非常小,其可以同時保有幾份尚在引用的舊版本配置,也能夠讓新的配置即刻生效。編譯後的舊版本配置通常在varnish重新開機時才會被丢棄,如果需要手動清理,則可以使用varnishadm的vcl.discard指令完成。
4、varnish的後端存儲
varnish支援多種不同類型的後端存儲,這可以在varnishd啟動時使用-s選項指定。後端存儲的類型包括:
(1)file:使用特定的檔案存儲全部的緩存資料,并通過作業系統的mmap()系統調用将整個緩存檔案映射至記憶體區域(如果條件允許);
(2)malloc:使用malloc()庫調用在varnish啟動時向作業系統申請指定大小的記憶體空間以存儲緩存對象;
(3)persistent(experimental):與file的功能相同,但可以持久存儲資料(即重新開機varnish資料時不會被清除);仍處于測試期;
varnish無法追蹤某緩存對象是否存入了緩存檔案,進而也就無從得知磁盤上的緩存檔案是否可用,是以,file存儲方法在varnish停止或重新開機時會清除資料。而persistent方法的出現對此有了一個彌補,但persistent仍處于測試階段,例如目前尚無法有效處理要緩存對象總體大小超出緩存空間的情況,是以,其僅适用于有着巨大緩存空間的場景。
選擇使用合适的存儲方式有助于提升系統性,從經驗的角度來看,建議在記憶體空間足以存儲所有的緩存對象時使用malloc的方法,反之,file存儲将有着更好的性能的表現。然而,需要注意的是,varnishd實際上使用的空間比使用-s選項指定的緩存空間更大,一般說來,其需要為每個緩存對象多使用差不多1K左右的存儲空間,這意味着,對于100萬個緩存對象的場景來說,其使用的緩存空間将超出指定大小1G左右。另外,為了儲存資料結構等,varnish自身也會占去不小的記憶體空間。
為varnishd指定使用的緩存類型時,-s選項可接受的參數格式如下:
malloc[,size] 或
file[,path[,size[,granularity]]] 或
persistent,path,size {experimental}
file中的granularity用于設定緩存空間配置設定機關,預設機關是位元組,所有其它的大小都會被圓整。
(二)Http協定與varnish
1、緩存相關的http首部
HTTP協定提供了多個首部用以實作頁面緩存及緩存失效的相關功能,這其中最常用的有:
(1)Expires:用于指定某web對象的過期日期/時間,通常為GMT格式;一般不應該将此設定的未來過長的時間,一年的長度對大多場景來說足矣;其常用于為純靜态内容如JavaScripts樣式表或圖檔指定緩存周期;
(2)Cache-Control:用于定義所有的緩存機制都必須遵循的緩存訓示,這些訓示是一些特定的指令,包括public、private、no-cache(表示可以存儲,但在重新驗正其有效性之前不能用于響應用戶端請求)、no-store、max-age、s-maxage以及must-revalidate等;Cache-Control中設定的時間會覆寫Expires中指定的時間;
(3)Etag:響應首部,用于在響應封包中為某web資源定義版本辨別符;
(4)Last-Mofified:響應首部,用于回應用戶端關于Last-Modified-Since或If-None-Match首部的請求,以通知用戶端其請求的web對象最近的修改時間;
(5)If-Modified-Since:條件式請求首部,如果在此首部指定的時間後其請求的web内容發生了更改,則伺服器響應更改後的内容,否則,則響應304(not modified);
(6)If-None-Match:條件式請求首部;web伺服器為某web内容定義了Etag首部,用戶端請求時能擷取并儲存這個首部的值(即标簽);而後在後續的請求中會通過If-None-Match首部附加其認可的标簽清單并讓伺服器端檢驗其原始内容是否有可以與此清單中的某标簽比對的标簽;如果有,則響應304,否則,則傳回原始内容;
(7)Vary:響應首部,原始伺服器根據請求來源的不同響應的可能會有所不同的首部,最常用的是Vary: Accept-Encoding,用于通知緩存機制其内容看起來可能不同于使用者請求時Accept-Encoding-header首部辨別的編碼格式;
(8)Age:緩存伺服器可以發送的一個額外的響應首部,用于指定響應的有效期限;浏覽器通常根據此首部決定内容的緩存時長;如果響應封包首部還使用了max-age指令,那麼緩存的有效時長為“max-age減去Age”的結果;
(三)Varnish狀态引擎(state engine)
VCL用于讓管理者定義緩存政策,而定義好的政策将由varnish的management程序分析、轉換成C代碼、編譯成二進制程式并連接配接至child程序。varnish内部有幾個所謂的狀态(state),在這些狀态上可以附加通過VCL定義的政策以完成相應的緩存處理機制,是以VCL也經常被稱作“域專用”語言或狀态引擎,“域專用”指的是有些資料僅出現于特定的狀态中。
1、VCL狀态引擎
在VCL狀态引擎中,狀态之間具有相關性,但彼此間互相隔離,每個引擎使用return(x)來退出目前狀态并訓示varnish進入下一個狀态。
varnish開始處理一個請求時,首先需要分析HTTP請求本身,比如從首部擷取請求方法、驗正其是否為一個合法的HTTP請求等。當這些基本分析結束後就需要做出第一個決策,即varnish是否從緩存中查找請求的資源。這個決定的實作則需要由VCL來完成,簡單來說,要由vcl_recv方法來完成。如果管理者沒有自定義vcl_recv函數,varnish将會執行預設的vcl_recv函數。然而,即便管理者自定義了vcl_recv,但如果沒有為自定義的vcl_recv函數指定其終止操作(terminating),其仍将執行預設的vcl_recv函數。事實上,varnish官方強烈建議讓varnish執行預設的vcl_recv以便處理自定義vcl_recv函數中的可能出現的漏洞。
2、VCL文法
VCL的設計參考了C和Perl語言,是以,對有着C或Perl程式設計經驗者來說,其非常易于了解。其基本文法說明如下:
(1)//、#或/* comment */用于注釋
(2)sub $name 定義函數
(3)不支援循環,有内置變量
(4)使用終止語句,沒有傳回值
(5)域專用
(6)操作符:=(指派)、==(等值比較)、~(模式比對)、!(取反)、&&(邏輯與)、||(邏輯或)
VCL的函數不接受參數并且沒有傳回值,是以,其并非真正意義上的函數,這也限定了VCL内部的資料傳遞隻能隐藏在HTTP首部内部進行。VCL的return語句用于将控制權從VCL狀态引擎傳回給
Varnish,而非預設函數,這就是為什麼VCL隻有終止語句而沒有傳回值的原因。同時,對于每個“域”來說,可以定義一個或多個終止語句,以告訴Varnish下一步采取何種操作,如查詢緩存或不查詢緩存等。
3、VCL的内置函數
VCL提供了幾個函數來實作字元串的修改,添加bans,重新開機VCL狀态引擎以及将控制權轉回Varnish等。
regsub(str,regex,sub)
regsuball(str,regex,sub):這兩個用于基于正規表達式搜尋指定的字元串并将其替換為指定的字元串;但regsuball()可以将str中能夠被regex比對到的字元串統統替換為sub,regsub()隻
替換一次;
ban(expression):
ban_url(regex):Bans所有其URL能夠由regex比對的緩存對象;
purge:從緩存中挑選出某對象以及其相關變種一并删除,這可以通過HTTP協定的PURGE方法完成;
hash_data(str):
return():當某VCL域運作結束時将控制權傳回給Varnish,并訓示Varnish如何進行後續的動作;其可以傳回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等;但
某特定域可能僅能傳回某些特定的指令,而非前面列出的全部指令;
return(restart):重新運作整個VCL,即重新從vcl_recv開始進行處理;每一次重新開機都會增加req.restarts變量中的值,而max_restarts參數則用于限定最大重新開機次數。
4、Vcl_recv
vcl_recv是在Varnish完成對請求封包的解碼為基本資料結構後第一個要執行的子例程,它通常有四個主要用途:
(1)修改用戶端資料以減少緩存對象差異性;比如删除URL中的www.等字元;
(2)基于用戶端資料選用緩存政策;比如僅緩存特定的URL請求、不緩存POST請求等;
(3)為某web應用程式執行URL重寫規則;
(4)挑選合适的後端Web伺服器;
可以使用下面的終止語句,即通過return()向Varnish傳回的訓示操作:
pass:繞過緩存,即不從緩存中查詢内容或不将内容存儲至緩存中;
pipe:不對用戶端進行檢查或做出任何操作,而是在用戶端與後端伺服器之間建立專用“管道”,并直接将資料在二者之間進行傳送;此時,keep-alive連接配接中後續傳送的資料也都将通過此
管道進行直接傳送,并不會出現在任何日志中;
lookup:在緩存中查找使用者請求的對象,如果緩存中沒有其請求的對象,後續操作很可能會将其請求的對象進行緩存;
error:由Varnish自己合成一個響應封包,一般是響應一個錯誤類資訊、重定向類資訊或負載均衡器傳回的後端web伺服器健康狀态檢查類資訊;
vcl_recv也可以通過精巧的政策完成一定意義上的安全功能,以将某些特定的攻擊扼殺于搖籃中。同時,它也可以檢查出一些拼寫類的錯誤并将其進行修正等。
Varnish預設的vcl_recv專門設計用來實作安全的緩存政策,它主要完成兩種功能:
(1)僅處理可以識别的HTTP方法,并且隻緩存GET和HEAD方法;
(2)不緩存任何使用者特有的資料;
安全起見,一般在自定義的vcl_recv中不要使用return()終止語句,而是再由預設vcl_recv進行處理,并由其做出相應的處理決策。
下面是一個自定義的使用示例:
<code>sub vcl_recv {</code>
<code>if</code> <code>(req.http.User-Agent ~ </code><code>"iPad"</code> <code>||</code>
<code>req.http.User-Agent ~ </code><code>"iPhone"</code> <code>||</code>
<code>req.http.User-Agent ~ </code><code>"Android"</code><code>) {</code>
<code>set</code> <code>req.http.X-Device = </code><code>"mobile"</code><code>;</code>
<code>} </code><code>else</code> <code>{</code>
<code>set</code> <code>req.http.X-Device = </code><code>"desktop"</code><code>;</code>
<code>}</code>
此例中的VCL建立一個X-Device請求首部,其值可能為mobile或desktop,于是web伺服器可以基于此完成不同類型的響應,以提高使用者體驗。
5、Vcl_fetch
如前面所述,相對于vcl_recv是根據用戶端的請求作出緩存決策來說,vcl_fetch則是根據伺服器端的響應作出緩存決策。在任何VCL狀态引擎中傳回的pass操作都将由vcl_fetch進行後續處理
。vcl_fetch中有許多可用的内置變量,比如最常用的用于定義某對象緩存時長的beresp.ttl變量。通過return()傳回給arnish的操作訓示有:
(1)deliver:緩存此對象,并将其發送給用戶端(經由vcl_deliver);
(2)hit_for_pass:不緩存此對象,但可以導緻後續對此對象的請求直接送達到vcl_pass進行處理;
(3)restart:重新開機整個VCL,并增加重新開機計數;超出max_restarts限定的最大重新開機次數後将會傳回錯誤資訊;
(4)error code [reason]:傳回指定的錯誤代碼給用戶端并丢棄此請求;
預設的vcl_fetch放棄了緩存任何使用了Set-Cookie首部的響應。
五、修剪緩存對象
1、緩存内容修剪
提高緩存命中率的最有效途徑之一是增加緩存對象的生存時間(TTL),但是這也可能會帶來副作用,比如緩存的内容在到達為其指定的有效期之間已經失效。是以,手動檢驗緩存對象的有效性或者重新整理緩存是緩存很有可能成為伺服器管理者的日常工作之一,相應地,Varnish為完成這類的任務提供了三種途徑:HTTP 修剪(HTTP purging)、禁用某類緩存對象(banning)和強制緩存未指令(forced cache misses)。
這裡需要特殊說明的是,Varnish 2中的purge()操作在Varnish 3中被替換為了ban()操作,而Varnish 3也使用了purge操作,但為其賦予了新的功能,且隻能用于vcl_hit或vcl_miss中替換Varnish 2中常用的set obj.ttl=0s。
在具體執行某清理工作時,需要事先确定如下問題:
(1)僅需要檢驗一個特定的緩存對象,還是多個?
(2)目的是釋放記憶體空間,還是僅替換緩存的内容?
(3)是不是需要很長時間才能完成内容替換?
(4)這類操作是個日常工作,還是僅此一次的特殊需求?
2、移除單個緩存對象
purge用于清理緩存中的某特定對象及其變種(variants),是以,在有着明确要修剪的緩存對象時可以使用此種方式。HTTP協定的PURGE方法可以實作purge功能,不過,其僅能用于vcl_hit和vcl_miss中,它會釋放記憶體工作并移除指定緩存對象的所有Vary:-變種,并等待下一個針對此内容的用戶端請求到達時重新整理此内容。另外,其一般要與return(restart)一起使用。下面是個在VCL中配置的示例。
<code>acl purgers {</code>
<code>"127.0.0.1"</code><code>;</code>
<code>"192.168.0.0"</code><code>/24</code><code>;</code>
<code>if</code> <code>(req.request == </code><code>"PURGE"</code><code>) {</code>
<code>if</code> <code>(!client.ip ~ purgers) {</code>
<code>error 405 </code><code>"Method not allowed"</code><code>;</code>
<code>return</code> <code>(lookup);</code>
<code>sub vcl_hit {</code>
<code>purge;</code>
<code>error 200 </code><code>"Purged"</code><code>;</code>
<code>sub vcl_miss {</code>
<code>error 404 </code><code>"Not in cache"</code><code>;</code>
<code>sub vcl_pass {</code>
<code>error 502 </code><code>"PURGE on a passed object"</code><code>;</code>
用戶端在發起HTTP請求時,隻需要為所請求的URL使用PURGE方法即可,其指令使用方式如下:
<code># curl -I PURGE http://varniship/path/to/someurl</code>
3、強制緩存未命中
在vcl_recv中使用return(pass)能夠強制到上遊伺服器取得請求的内容,但這也會導緻無法将其緩存。使用purge會移除舊的緩存對象,但如果上遊伺服器當機而無法取得新版本的内容時,此内容将無法再響應給用戶端。使用req.has_always_miss=ture,可以讓Varnish在緩存中搜尋相應的内容但卻總是回應“未命中”,于是vcl_miss将後續地負責啟動vcl_fetch從上遊伺服器取得新内容,并以新内容緩存覆寫舊内容。此時,如果上遊伺服器當機或未響應,舊的内容将保持原狀,并能夠繼續服務于那些未使用req.has_always_miss=true的用戶端,直到其過期失效或由其它方法移除。
4、Banning
ban()是一種從已緩存對象中過濾(filter)出某此特定的對象并将其移除的緩存内容重新整理機制,不過,它并不阻止新的内容進入緩存或響應于請求。在Varnish中,ban的實作是指将一個ban添加至ban清單(ban-list)中,這可以通過指令行接口或VCL實作,它們的使用文法是相同的。ban本身就是一個或多個VCL風格的語句,它會在Varnish從緩存哈希(cache hash)中查找某緩存對象時對搜尋的對象進行比較測試,是以,一個ban語句就是類似比對所有“以/downloads開頭的URL”,或“響應首部中包含nginx的對象”。例如:
<code>ban req.http.host == </code><code>"xxx.com"</code> <code>&& req.url ~ </code><code>"\.gif$"</code>
定義好的所有ban語句會生成一個ban清單(ban-list),新添加的ban語句會被放置在清單的首部。緩存中的所有對象在響應給用戶端之前都會被ban清單檢查至少一次,檢查完成後将會為每個緩存建立一個指向與其比對的ban語句的指針。Varnish在從緩存中擷取對象時,總是會檢查此緩存對象的指針是否指向了ban清單的首部。如果沒有指向ban清單的首部,其将對使用所有的新添加的ban語句對此緩存對象進行測試,如果沒有任何ban語句能夠比對,則更新ban清單。
對ban這種實作方式持反對意見有有之,持贊成意見者亦有之。反對意見主要有兩種,一是ban不會釋放記憶體,緩存對象僅在有用戶端通路時被測試一次;二是如果緩存對象曾經被通路到,但卻很少被再次通路時ban清單将會變得非常大。贊成的意見則主要集中在ban可以讓Varnish在恒定的時間内完成向ban清單添加ban的操作,例如在有着數百萬個緩存對象的場景中,添加一個ban也隻需要在恒定的時間内即可完成。其實作方法本處不再詳細說明。
六、Varnish檢測後端主機的健康狀态
Varnish可以檢測後端主機的健康狀态,在判定後端主機失效時能自動将其從可用後端主機清單中移除,而一旦其重新變得可用還可以自動将其設定為可用。為了避免誤判,Varnish在探測後端主機的健康狀态發生轉變時(比如某次探測時某後端主機突然成為不可用狀态),通常需要連續執行幾次探測均為新狀态才将其标記為轉換後的狀态。
每個後端伺服器目前探測的健康狀态探測方法通過.probe進行設定,其結果可由req.backend.healthy變量擷取,也可通過varnishlog中的Backend_health檢視或varnishadm的debug.health檢視。
<code>backend web1 {</code>
<code>.host = </code><code>"www.xxx.com"</code><code>;</code>
<code>.probe = {</code>
<code>.url = </code><code>"/.healthtest.html"</code><code>;</code>
<code>.interval = 1s;</code>
<code>.window = 5;</code>
<code>.threshold = 2;</code>
.probe中的探測指令常用的有:
(1) .url:探測後端主機健康狀态時請求的URL,預設為“/”;
(2) .request: 探測後端主機健康狀态時所請求内容的詳細格式,定義後,它會替換.url指定的探測方式;比如:
<code>.request =</code>
<code>"GET /.healthtest.html HTTP/1.1"</code>
<code>"Host: www.xxx.com"</code>
<code>"Connection: close"</code><code>;</code>
(3) .window:設定在判定後端主機健康狀态時基于最近多少次的探測進行,預設是8;
(4) .threshold:在.window中指定的次數中,至少有多少次是成功的才判定後端主機正健康運作;預設是3;
(5) .initial:Varnish啟動時對後端主機至少需要多少次的成功探測,預設同.threshold;
(6) .expected_response:期望後端主機響應的狀态碼,預設為200;
(7) .interval:探測請求的發送周期,預設為5秒;
(8) .timeout:每次探測請求的過期時長,預設為2秒
是以,如上示例中表示每隔1秒對此後端主機www.xxx.com探測一次,請求的URL為http://www.xxx.com/.healthtest.html,在最近5次的探測請求中至少有2次是成功的(響應碼為200)就判定此後端主機為正常工作狀态。
如果Varnish在某時刻沒有任何可用的後端主機,它将嘗試使用緩存對象的“寬容副本”(graced copy),當然,此時VCL中的各種規則依然有效。是以,更好的辦法是在VCL規則中判斷req.backend.healthy變量顯示某後端主機不可用時,為此後端主機增大req.grace變量的值以設定适用的寬容期限長度。
七、varnish使用多台後端主機
Varnish中可以使用director指令将一個或多個近似的後端主機定義為一個邏輯組,并可以指定的排程方式(也叫挑選方法)來輪流将請求發送至這些主機上。不同的director可以使用同一個後端主機,而某director也可以使用“匿名”後端主機(在director中直接進行定義)。每個director都必須有其專用名,且在定義後必須在VCL中進行調用,VCL中任何可以指定後端主機的位置均可以按需将其替換為調用某已定義的director。
<code>.host = </code><code>"backweb1.xxx.com"</code><code>;</code>
<code>.port = </code><code>"80"</code><code>;</code>
<code>director webservers random {</code>
<code> </code><code>.retries = 5;</code>
<code> </code><code>{</code>
<code> </code><code>.backend = web1;</code>
<code> </code><code>.weight = 2;</code>
<code> </code><code>}</code>
<code> </code><code>.backend = {</code>
<code> </code><code>.host = </code><code>"backweb2.xxx.com"</code><code>;</code>
<code> </code><code>.port = </code><code>"80"</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>.weight = 3;</code>
如上示例中,web1為顯式定義的後端主機,而webservers這個directors還包含一個“匿名”後端主機(backweb2.xxx.com)。webservers從這兩個後端主機中挑選一個主機的方法為random,即以随機方式挑選。
Varnish的director支援的挑選方法中比較簡單的有round-robin和random兩種。其中,round-robin類型沒有任何參數,隻需要為其指定各後端主機即可,挑選方式為“輪叫”,并在某後端主機故障時不再将其視為挑選對象;random方法随機從可用後端主機中進行挑選,每一個後端主機都需要一個.weight參數以指定其權重,同時還可以dirctor級别使用,.retires參數來設定查找一個健康後端主機時的嘗試次數。
Varnish 2.1.0後,random挑選方法又多了兩種變化形式client和hash。client類型的director使用client.identity作為挑選因子,這意味着client.identity相同的請求都将被發送至同一個後端主機。client.identity預設為cliet.ip,但也可以在VCL中将其修改為所需要的辨別符。類似地,hash類型的director使用hash資料作為挑選因子,這意味着對同一個URL的請求将被發往同一個後端主機,其常用于多級緩存的場景中。然而,無論是client還hash,當其傾向于使用後端主機不可用時将會重新挑選新的後端其機。
八、varnish管理進階
1、可調參數
Varnish有許多參數,雖然大多數場景中這些參數的預設值都可以工作得很好,然而特定的工作場景中要想有着更好的性能的表現,則需要調整某些參數。可以在管理接口中使用param.show指令檢視這些參數,而使用param.set則能修改這些參數的值。然而,在指令行接口中進行的修改不會儲存至任何位置,是以,重新開機varnish後這些設定會消失。此時,可以通過啟動腳本使用-p選項在varnishd啟動時為其設定參數的值。然而,除非特别需要對其進行修改,保持這些參數為預設值可以有效降低管理複雜度。
2、共享記憶體日志
共享記憶體日志(shared memory log)通常被簡稱為shm-log,它用于記錄日志相關的資料,大小為80M。varnish以輪轉(round-robin)的方式使用其存儲空間。一般不需要對shm-log做出更多的設定,但應該避免其産生I/O,這可以使用tmpfs實作,其方法為在/etc/fstab中設定一個挂載至/var/lib/varnish目錄(或其它自定義的位置)臨時檔案系統即可。
3、線程模型(Trheading model)
varnish的child程序由多種不同的線程組成,分别用于完成不同的工作。例如:
cache-worker線程:每連接配接一個,用于處理請求;
cache-main線程:全局隻有一個,用于啟動cache;
ban lurker線程:一個,用于清理bans;
acceptor線程:一個,用于接收新的連接配接請求;
epoll/kqueue線程:數量可配置,預設為2,用于管理線程池;
expire線程:一個,用于移除老化的内容;
backend poll線程:每個後端伺服器一個,用于檢測後端伺服器的健康狀況;
在配置varnish時,一般隻需為關注cache-worker線程,而且也隻能配置其線程池的數量,而除此之外的其它均非可配置參數。與此同時,線程池的數量也隻能在流量較大的場景下才需要增加,而且經驗表明其多于2個對提升性能并無益處。
4、線程相關的參數(Threading parameters)
varnish為每個連接配接使用一個線程,是以,其worker線程的最大數決定了varnish的并發響應能力。下面是線程池相關的各參數及其配置:
<code>thread_pool_add_delay 2 [milliseconds]</code>
<code>thread_pool_add_threshold 2 [requests]</code>
<code>thread_pool_fail_delay 200 [milliseconds]</code>
<code>thread_pool_max 500 [threads]</code>
<code>thread_pool_min 5 [threads]</code>
<code>thread_pool_purge_delay 1000 [milliseconds]</code>
<code>thread_pool_stack 65536 [bytes]</code>
<code>thread_pool_timeout 120 [seconds]</code>
<code>thread_pool_workspace 16384 [bytes]</code>
<code>thread_pools 2 [pools]</code>
<code>thread_stats_rate 10 [requests]</code>
其中最關鍵的當屬thread_pool_max和thread_pool_min,它們分别用于定義每個線程池中的最大線程數和最少線程數。是以,在某個時刻,至少有thread_pool_min*thread_pools個worker線程在運作,但至多不能超出thread_pool_max*thread_pools個。根據需要,這兩個參數的數量可以進行調整,varnishstat指令的n_wrk_queued可以顯示目前varnish的線程數量是否足夠,如果隊列中始終有不少的線程等待運作,則可以适當調大thread_pool_max參數的值。但一般建議每台varnish伺服器上最多運作的worker線程數不要超出5000個。
當某連接配接請求到達時,varnish選擇一個線程池負責處理此請求。而如果此線程池中的線程數量已經達到最大值,新的請求将會被放置于隊列中或被直接丢棄。預設線程池的數量為2,這對最繁忙的varnish伺服器來說也已經足夠。
九、Varnish的指令行工具
1、varnishadm指令
<code>指令文法:varnishadm [-t timeout] [-S secret_file] [-T address:port] [-n name] [</code><code>command</code> <code>[...]]</code>
通過指令行的方式連接配接至varnishd進行管理操作的工具,指定要連接配接的varnish執行個體的方法有兩種:
-n name —— 連接配接至名稱為“name”的執行個體;
-T address:port —— 連接配接至指定套接字上的執行個體;
其運作模式有兩種,當不在指令行中給出要執行的"command"時,其将進入互動式模式;否則,varnishadm将執行指定的"command"并退出。要檢視本地啟用的緩存,可使用如下指令進行。
<code># varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 storage.list</code>
本文轉自 SoulMio 51CTO部落格,原文連結:http://blog.51cto.com/bovin/1854143,如需轉載請自行聯系原作者