Varnish理論知識php
1、Varnish 簡介
css
Varnish 是一款高性能且開源的反向代理服務器和 HTTP 加速器,其採用全新的軟件體系機構,和如今的硬件體系緊密配合,與傳統的 squid 相比,varnish 具備性能更高、速度更快、管理更加方便等諸多優勢,不少大型的網站都開始嘗試使用 varnish 來替換 squid,這些都促進 varnish 迅速發展起來。html
挪威的最大的在線報紙 Verdens Gang(vg.no) 使用 3 臺 Varnish 代替了原來的 12 臺 Squid,性能比之前更好,這是 Varnish 最成功的應用案例。目前,Varnish能夠在FreeBSD6.0/7.0、solaris、 Linux2.6內核上運行。nginx
2、Varnish與Squid的對比web
下面是Varnish與Squid之間的相同點。正則表達式
都是一個反向代理服務器。算法
都是開源軟件。編程
下面是它們的不一樣點,也是Varnish的優勢。vim
Varnish的穩定性很高。二者在完成相同負荷的工做時,Squid服務器發生故障的概率要高於Varnish,由於Squid須要常常重啓。後端
Varnish訪問速度更快。Varnish採用了「Visual Page Cache」技術,全部緩存數據都直接從內存讀取,而Squid是從硬盤讀取緩存數據,所以Varnish在訪問速度方面會更快。
Varnish能夠支持更多的併發鏈接。由於Varnish的TCP鏈接釋放要比Squid快,因此在高併發鏈接狀況下能夠支持更多的TCP鏈接。
Varnish能夠經過管理端口,使用正則表達式批量清除部分緩存,而Squid作不到。
固然,與傳統的Squid相比,Varnish也有缺點。
Varnish在高併發狀態下CPU、I/O和內存等資源開銷都高於Squid。
Varnish進程一旦掛起、崩潰或者重啓,緩存數據都會從內存中徹底釋放,此時全部請求都會被髮送到後端服務器,在高併發狀況下,這會給後端服務器形成很大壓力。
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、VCL內置函數
(1)vcl_recv函數
用於接收和處理請求,當請求到達併成功接收後被調用,經過判斷請求的數據來決定如何處理請求。
此函數通常以以下幾個關鍵字結束:
pass:表示進入pass模式,把請求控制權交給vcl_pass函數。
pipe:表示進入pipe模式,把請求控制權交給vcl_pipe函數。
error code [reason]:表示返回「code」給客戶端,並放棄處理該請求,「code」是錯誤標識,例如200、405等,「reason」是錯誤提示信息。
(2)vcl_pipe函數
此函數在進入pipe模式時被調用,用於將請求直接傳遞至後端主機,在請求和返回的內容沒有改變的狀況下,將不變的內容返回給客戶端,直到這個連接關閉。
此函數通常以以下幾個關鍵字結束:
error code [reason]
pipe:表示進入pipe模式,把請求控制權交給vcl_pipe函數。
(3)vcl_hit函數
在執行lookup指令後,若是在緩存中找到請求的內容,將自動調用該函數。
此函數通常以以下幾個關鍵字結束:
deliver:表示將找到的內容發送給客戶端,並把控制權交給函數vcl_deliver。
error code [reason]
pass
(4)vcl_miss函數
在執行lookup指令後,若是沒有在緩存中找到請求的內容時自動調用該方法,此函數能夠用於判斷是否須要從後端服務器取內容。
此函數通常以以下幾個關鍵字結束:
fetch:表示從後端獲取請求的內容,並把控制權交給vcl_fetch函數。
error code [reason]
pass
(5)vcl_pass函數
此函數在進入pass模式時被調用,用於將請求直接傳遞至後端主機,後端主機應答數據後送給客戶端,但不進行任何緩存,在當前鏈接下每次都返回最新的內容。
此函數通常以以下幾個關鍵字結束:
error code [reason]
pass
lookup :表示在緩存裏查找被請求的對象,而且根據查找的結果把控制權交給函數vcl_hit或者函數vcl_miss。
(6)vcl_fetch函數
在從後端主機更新緩存而且獲取內容後調用該方法,接着,經過判斷獲取的內容來決定是否將內容放入緩存,仍是直接返回給客戶端。
此函數通常以以下幾個關鍵字結束:
error code [reason]
pass
deliver
(7)vcl_deliver函數
在緩存中找到請求的內容後,發送給客戶端前調用此方法。此函數通常以以下幾個關鍵字結束:
error code [reason]
deliver
(8)vcl_timeout 函數
此函數在緩存內容到期前調用。通常以以下幾個關鍵字結束:
discard:表示從緩存中清除該內容。
fetch
(9)vcl_discard函數
在緩存內容到期後或緩存空間不夠時,自動調用該方法,通常以以下幾個關鍵字結束:
keep:表示將內容繼續保留在緩存中。
discard
看到這麼多的函數是否是有點頭暈呢。。。其實它們彼此之間是有關係的,下面咱們看一下它們的流程圖。。
5、VCL處理流程圖
處理過程大體分爲以下幾個步驟:
(1) Receive狀態,也就是請求處理的入口狀態,根據VCL規則判斷該請求應該是Pass或Pipe,或者進入Lookup(本地查詢)。
(2) Lookup狀態,進入此狀態後,會在hash表中查找數據,若找到,則進入Hit狀態,不然進入miss狀態。
(3) Pass狀態,在此狀態下,會進入後端請求,即進入fetch狀態,在此狀態下不進行任何緩存
(4) Fetch狀態,在Fetch狀態下,對請求進行後端的獲取,發送請求,得到數據,更具VCL規則判斷請求應該是 deliver仍是pass。
(5) Deliver狀態, 將獲取到的數據發送給客戶端,而後完成本次請求。
6、內置公用變量
VCL內置的公用變量能夠用在不一樣的VCL函數中,根據這些公用變量使用的不一樣階段,下面依次介紹。
當請求到達後,可使用的公用變量如表2所示:
表2
公用變量名稱 含義
req.backend 指定對應的後端主機
server.ip 表示服務器端IP
client.ip 表示客戶端IP
req.request 指定請求的類型,例如GET、HEAD、POST等
req.url 指定請求的地址
req.proto 表示客戶端發起請求的HTTP協議版本
req.http.header 表示對應請求中的http頭部信息
req. restarts 表示請求重啓的次數,默認最大值爲4
Varnish 在向後端主機請求時,可使用的公用變量如表3所示:
表3
公用變量名稱 含義
beresp.request 指定請求的類型,例如GET、HEAD等
beresp.url 指定請求的地址
beresp .proto 表示客戶端發起請求的HTTP協議版本
beresp .http.header 表示對應請求中的http頭部信息
beresp .ttl 表示緩存的生存週期,也就是cache保留多長時間,單位是秒
從cache或者後端主機獲取內容後,可使用的公用變量如表4所示:
表4
公用變量名稱 含義
obj.status 表示返回內容的請求狀態代碼,例如200、30二、504等
obj.cacheable 表示返回的內容是否能夠緩存,也就是說,若是HTTP返回是200、20三、300、30一、30二、40四、 410等,而且有非0的生存期,則能夠緩存
obj.valid 表示是不是有效的HTTP應答
obj.response 表示返回內容的請求狀態信息
obj.proto 表示返回內容的HTTP協議版本
obj.ttl 表示返回內容的生存週期,也就是緩存時間,單位是秒
obj.lastuse 表示返回上一次請求到如今的間隔時間,單位是秒
對客戶端應答時,可使用的公用變量如表5所示:
表5
公用變量名稱 含義
resp.status 表示返回給客戶端的HTTP狀態代碼
resp.proto 表示返回給客戶端的HTTP協議版本
resp.http.header 表示返回給客戶端的HTTP頭部信息
resp.response 表示返回給客戶端的HTTP狀態信息
以上變量只是varnish的經常使用變量,如需更多變量請訪問Varnish官網
7、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用於設定緩存空間分配單位,默認單位是字節,全部其它的大小都會被圓整。
8、Varnish支持的算法
Varnish的director支持的挑選方法中比較簡單的有round-robin和random兩種。其中,round-robin類型沒有任何參數,只須要爲其指定各後端主機便可,挑選方式爲「輪叫」,並在某後端主機故障時再也不將其視做挑選對象;random方法隨機從可用後端主機中進行挑選,每個後端主機都須要一個.weight參數以指定其權重,同時還能夠director級別使用.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的安裝與配置
一、Varnish安裝(rpm包軟件)
rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el6/noarch/varnish-release-3.0-1.el6.noarch.rpm yum install varnish varnish-libs-devel -y
若有安裝疑惑請訪問varnish官網https://www.varnish-cache.org/installation/redha
二、Varnish目錄結構
/etc/sysconfig/varnish #存放Varnish運行參數設置 /etc/varnish/ #存放Varnish VCL配置文件
三、Varnish配置基本實例
3.一、修改 /etc/sysconfig/varnish
vim /etc/sysconfig/varnish #VARNISH_VCL_CONF=/etc/varnish/default.vcl VARNISH_VCL_CONF=/etc/varnish/test.vcl #調用test.vcl文件 VARNISH_LISTEN_PORT=80 #改成80端口 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 #監聽地址 VARNISH_ADMIN_LISTEN_PORT=6082 #管理端口 VARNISH_SECRET_FILE=/etc/varnish/secret #密鑰文件
3.二、提供/etc/
var
nish/test.vcl
cd /etc/varnish/ cp default.vcl test.vcl #複製默認配置文件
3.三、配置
/etc/
var
nish/test.vcl
############定義健康狀態檢測############### probe healthcheck { .url = "/"; #定義健康檢查的頁面 .interval = 6s; #探測請求的發送週期,默認爲5秒; .timeout = 0.3 s; #每次探測請求的過時時長 .window = 8; #設定在斷定後端主機健康狀態時基於最近多少次的探測進行 .threshold = 3; #在.window中指定的次數中,至少有多少次是成功的才斷定後端主機正健康運行 .initial = 3; #Varnish啓動時對後端主機至少須要多少次的成功探測,默認同.threshold; } ############定義兩組服務器############## backend web1 { .host = "172.16.10.7"; #服務器主機 .port = "80"; #服務器端口 .probe = healthcheck; #健康狀態檢測 } backend web2 { .host = "172.16.10.3"; .port = "80"; .probe = healthcheck; } backend app1 { .host = "172.16.10.7"; .port = "8080"; .probe = healthcheck; } backend app2 { .host = "172.16.10.3"; .port = "8080"; .probe = healthcheck; } ############定義集羣,調用服務器############## director webserver random { #定義一個名爲webserver的directory,由web1,和web2分但請求,使用random算法,處理靜態請求 {.backend = web1; .weight = 2; #設置權重爲2 } {.backend = web2; .weight = 5; } } director appserver random { #定義一個名爲appserver的directory,由app1,和app2分但請求,使用random算法,處理動態請求 {.backend = app1; .weight = 2;} {.backend = app2; .weight = 5;} } ############定義Acl############## acl purgers { #設置清理緩存的IP "127.0.0.1"; "172.16.10.0"/16; } ############vcl_recv函數段############## sub vcl_recv { #############使得後端服務能記錄訪問者的真實IP############ if (req.http.x-forwarded-for) { #添加首部信息 set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } #############配置動靜分離##################### if (req.url ~ "\.php$"){ set req.backend = appserver; #php結尾的交給appserver服務器組處理,不然交給webserver服務器組處理 }else{ set req.backend = webserver; } #############不正常的訪問不緩存############ if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } if (req.request != "GET" && req.request != "HEAD") { /* We only deal with GET and HEAD by default */ return (pass); } #############不緩存認證信息和Cookie############ if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } #############定義清楚緩存IP,調用上面的Acl############ if (req.request == "PURGE"){ #使用PURGE命令清除緩存 if(!client.ip ~ purgers){ #非ACl定義的IP,則不能清除緩存 error 405 "Method not allowed"; } return (lookup); } ############支持壓縮功能################### if (req.http.Accept-Encoding) { if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { # No point in compressing these remove req.http.Accept-Encoding; } else if (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } else if (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { remove req.http.Accept-Encoding; } } } ############vcl_hit函數段############## sub vcl_hit { if (req.request == "PURGE"){ #請求方法是PURGE,這清理緩存 purge; error 200 "Purged"; } } ############vcl_miss函數段############## sub vcl_miss { if (req.request == "PURGE"){ purge; error 404 "Not in cache"; } } ############vcl_pass函數段############## sub vcl_pass { if (req.request == "PURGE"){ error 502 "PURGE on a passed object"; } } ############vcl_fetch函數段############## sub vcl_fetch { #############定義緩存時長############ if (req.request == "GET" && req.url ~ "\.html$"){ set beresp.ttl = 300s; #超時時長爲300秒 if (req.request == "GET" && req.url ~ "\.(png|xsl|xml|pdf|ppt|doc|docx|chm|rar|zip|bmp|jpeg|swf|ico|mp3|mp4|rmvb|ogg|mov|avi|wmv|swf|txt|png|gif|jpg|css|js|html|htm)$") { set beresp.ttl = 600s; } return (deliver); } } ############vcl_deliver函數段############## sub vcl_deliver { #########定義Header標識,判斷緩存是否命中######### if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; #命中則返回HIT } else { set resp.http.X-Cache = "MISS"; #未命中則返回MISS } }
三、4啓動Varnish服務
/etc/init.d/varnish start
四、訪問測試(查看是否命中)
緩存命中率的高低,直接反映Varnish的運行狀態,如下經過varnishstat命令查看狀態信息
[root@nginx2 varnish]# varnishstat itrate ratio: 1 1 1 Hitrate avg: 0.6771 0.6771 0.6771 368 0.00 0.01 client_conn - Client connections accepted 824 0.00 0.02 client_req - Client requests received 369 0.00 0.01 cache_hit - Cache hits 176 0.00 0.01 cache_miss - Cache misses 95 0.00 0.00 backend_conn - Backend conn. success 83 0.00 0.00 backend_unhealthy - Backend conn. not attempted 33 0.00 0.00 backend_fail - Backend conn. failures 260 0.00 0.01 backend_reuse - Backend conn. reuses 51 0.00 0.00 backend_toolate - Backend conn. was closed 315 0.00 0.01 backend_recycle - Backend conn. recycles 222 0.00 0.01 fetch_length - Fetch with Length 20 0.00 0.00 fetch_chunked - Fetch chunked 96 0.00 0.00 fetch_304 - Fetch no body (304) 16 . . n_sess_mem - N struct sess_mem 3 . . n_objectcore - N struct objectcore 3 . . n_objecthead - N struct objecthead 4 . . n_waitinglist - N struct waitinglist 4 . . n_vbc - N struct vbc 100 . . n_wrk - N worker threads 100 0.00 0.00 n_wrk_create - N worker threads created 7 . . n_backend - N backends 86 . . n_expired - N expired objects 130 . . n_lru_moved - N LRU moved objects 453 0.00 0.01 n_objwrite - Objects sent with write 368 0.00 0.01 s_sess - Total Sessions 824 0.00 0.02 s_req - Total Requests 17 0.00 0.00 s_pipe - Total pipe 252 0.00 0.01 s_pass - Total pass 338 0.00 0.01 s_fetch - Total fetch 221522 0.00 6.37 s_hdrbytes - Total header bytes
註釋:
Client connections accepted:表示客戶端向反向代理服務器成功發送HTTP請求的總數量
Client requests received: 表示到如今爲止,瀏覽器向反向代理服務器發送HTTP請求的累積次數,因爲可能會使用長鏈接,因此這個值通常會大 於「Client connections accepted」。
Cache hits:表示反向代理服務器在緩存區中查找而且命中緩存的次數。
Cache misses:表示直接訪問後端主機的請求數量,也就是非命中數。
N struct object:表示當前被緩存的數量。
N expired objects:表示過時的緩存內容數量。
N LRU moved objects:表示被淘汰的緩存內容個數
2、Varnish 管理
一、手動清除緩存
[root@nginx2 varnish]# curl -X PURGE http://172.16.10.2/index.html <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>200 Purged</title> </head> <body> <h1>Error 200 Purged</h1> <p>Purged</p> <h3>Guru Meditation:</h3> <p>XID: 1003529630</p> <hr> <p>Varnish cache server</p> </body> </html>
二、查看varnish日誌
[root@nginx2 varnish]# varnishlog 0 Backend_health - app Still healthy 4--X-RH 8 3 8 0.011716 0.014211 HTTP/1.1 200 OK 0 Backend_health - app1 Still healthy 4--X-RH 8 3 8 0.016078 0.014856 HTTP/1.1 200 OK
三、 varnishadm 命令
[root@nginx2 varnish]# varnishadm varnish> help 200 help [command] ping [timestamp] auth response quit banner status #查看狀態 start #啓動varnish stop #關閉varnish vcl.load <configname> <filename> #動態加載vcl vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> #動態使用vcl vcl.discard <configname> vcl.list #查看使用的vcl vcl.show <configname> #查看vcl的配置 param.show [-l] [<param>] param.set <param> <value> panic.show panic.clear storage.list backend.list backend.set_health matcher state ban.url <regexp> ban <field> <operator> <arg> [&& <field> <oper> <arg>]... ban.list
3、Varnish性能優化
Varnish有許多參數,雖然大多數場景中這些參數的默認值均可以工做得很好,然而特定的工做場景中要想有着更好的性能的表現,則須要調整某些參數。能夠在管理接口中使用param.show命令查看這些參數,而使用param.set則能修改這些參數的值。然而,在命令行接口中進行的修改不會保存至任何位置,所以,重啓varnish後這些設定會消失。此時,能夠經過啓動腳本使用-p選項在varnishd啓動時爲其設定參數的值。然而,除非特別須要對其進行修改,保持這些參數爲默認值能夠有效下降管理複雜度,因爲Varnish的參數有不少,此處指對影響較大的參數進行介紹須要更加詳細的介紹需查看官方文檔
[root@nginx2 varnish]# varnishadm varnish> param.show listen_depth 1024 [connections] lru_interval 2 [seconds] thread_pool_max 1000 [threads] thread_pool_min 50 [threads] thread_pool_timeout 120 [seconds] thread_pools 2 [pools] varnish>
註釋:
本博客至此結束,若有不足之處,望廣大博友多提寶貴意見。。。