高性能HTTP加速器Varnish(安裝配置篇)
一、安裝Varnish
Varnish的安裝非常簡(jiǎn)單,下面逐步介紹:
1、安裝前的準(zhǔn)備
Varnish安裝環(huán)境如下表1所示:
表1
主機(jī)名 操作系統(tǒng) IP地址
Varnish-server CentOS release 5.4 192.168.12.246
Web-server CentOS release 5.4 192.168.12.26
接著,建立varnish用戶以及用戶組,并且創(chuàng)建Varnish緩存目錄和日志目錄:
[root@varnish-server ~]#useradd -s /sbin/nologin varnish
[root@varnish-server ~]#mkdir /data/varnish/cache
[root@varnish-server ~]#mkdir /data/varnish/log
[root@varnish-server ~]#chown -R varnish:varnish /data/varnish/cache
[root@varnish-server ~]#chown -R varnish:varnish /data/varnish/log
2、獲取varnish軟件
Varnish的官方站點(diǎn)為http://varnish-cache.org, 這里面有varnish的最新說(shuō)明文檔,以及版本升級(jí)記錄,從此站點(diǎn)可以找到varnish在SourceForge的下載鏈接,目前,varnish的 最新版本是Varnish 2.1.2,下載完成后的包名為varnish-2.1.2.tar.gz,此處我們就以此版本為例,進(jìn)行安裝配置。
3、安裝pcre
如果沒(méi)有安裝Pcre,在編譯varnish2.0以上版本時(shí),會(huì)提示找不到pcre庫(kù),而pcre庫(kù)是為了兼容正則表達(dá)式,所以必須先安裝pcre庫(kù)。
[root@varnish-server ~]#tar zxvf pcre-7.9.tar.gz
[root@varnish-server ~]#cd pcre-7.9/
[root@varnish-server ~]#./configure --prefix=/usr/local/pcre/
[root@varnish-server ~]#make && make install
4、安裝varnish
這里我們將varnish安裝到/usr/local/目錄下,操作如下:
[root@varnish-server ~]#tar -zxvf varnish-2.1.2.tar.gz
[root@varnish-server ~]#cd varnish-2.1.2
[root@varnish-server ~]#export PKG_CONFIG_PATH=/usr/local/pcre/lib/pkgconfig
[root@varnish-server ~]#./configure --prefix=/usr/local/varnish \
>--enable-dependency-trackin
>--enable-debugging-symbols
>--enable-developer-warnings
[root@varnish-server ~]#make
[root@varnish-server ~]#make install
[root@varnish-server ~]#cp redhat/varnish.initrc /etc/init.d/varnish
[root@varnish-server ~]#cp redhat/varnish.sysconfig /etc/sysconfig/varnish
其中,“PKG_CONFIG_PATH”是指定varnish查找pcre庫(kù)的路徑,如果pcre安裝在了其它路徑下,在這里指定相應(yīng)的路徑即 可,Varnish默認(rèn)查找的pcre庫(kù)路徑為/usr/local/lib/ pkgconfig。最后兩步操作是拷貝一些varnish守護(hù)進(jìn)程的初始化腳本文件,這些腳本用于varnish的啟動(dòng)、關(guān)閉管理等方面,在下面章節(jié)中 會(huì)進(jìn)行詳細(xì)講解。
至此,varnish安裝完畢。
二、配置Varnish
1、VCL使用說(shuō)明
VCL,即為Varnish Configuation Language,用來(lái)定義varnish的存取策略,VCL語(yǔ)法比較簡(jiǎn)單,跟C和perl比較相似,可以使用指定運(yùn)算符“=”,比較運(yùn)算符“==”,邏 輯運(yùn)算符“!,&&,!!”等形式。還支持正則表達(dá)樣和用“~”進(jìn)行ACL匹配運(yùn)算,同時(shí)還可以使用“set”這樣的關(guān)鍵字來(lái)指定變量。
需要注意的是,“\”字符在VCL里沒(méi)有特別的含義,這點(diǎn)與其它語(yǔ)言略有不同,另外,VCL只是配置,并不是真正的編程語(yǔ)言,沒(méi)有循環(huán),也沒(méi)有自定義變量。
在講述Varnish配置之前,首先需要了解下varnish的配置語(yǔ)法,即VCL,下面對(duì)VCL常用的一些內(nèi)置函數(shù)和公用變量進(jìn)行詳細(xì)介紹。
VCL內(nèi)置函數(shù)
(1)vcl_recv函數(shù)
用于接收和處理請(qǐng)求,當(dāng)請(qǐng)求到達(dá)并成功接收后被調(diào)用,通過(guò)判斷請(qǐng)求的數(shù)據(jù)來(lái)決定如何處理請(qǐng)求。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
pass:表示進(jìn)入pass模式,把請(qǐng)求控制權(quán)交給vcl_pass函數(shù)。
pipe:表示進(jìn)入pipe模式,把請(qǐng)求控制權(quán)交給vcl_pipe函數(shù)。
error code [reason]:表示返回“code”給客戶端,并放棄處理該請(qǐng)求,“code”是錯(cuò)誤標(biāo)識(shí),例如200、405等,“reason”是錯(cuò)誤提示信息。
(2)vcl_pipe函數(shù)
此函數(shù)在進(jìn)入pipe模式時(shí)被調(diào)用,用于將請(qǐng)求直接傳遞至后端主機(jī),在請(qǐng)求和返回的內(nèi)容沒(méi)有改變的情況下,將不變的內(nèi)容返回給客戶端,直到這個(gè)鏈接關(guān)閉。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
error code [reason]
pipe
(3)vcl_pass函數(shù)
此函數(shù)在進(jìn)入pass模式時(shí)被調(diào)用,用于將請(qǐng)求直接傳遞至后端主機(jī),后端主機(jī)應(yīng)答數(shù)據(jù)后送給客戶端,但不進(jìn)行任何緩存,在當(dāng)前連接下每次都返回最新的內(nèi)容。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
error code [reason]
pass
(4)lookup
表示在緩存里查找被請(qǐng)求的對(duì)象,并且根據(jù)查找的結(jié)果把控制權(quán)交給函數(shù)vcl_hit或者函數(shù)vcl_miss。
(5)vcl_hit函數(shù)
在執(zhí)行l(wèi)ookup指令后,如果在緩存中找到請(qǐng)求的內(nèi)容,將自動(dòng)調(diào)用該函數(shù)。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
deliver:表示將找到的內(nèi)容發(fā)送給客戶端,并把控制權(quán)交給函數(shù)vcl_deliver。
error code [reason]
pass
(6)vcl_miss函數(shù)
在執(zhí)行l(wèi)ookup指令后,如果沒(méi)有在緩存中找到請(qǐng)求的內(nèi)容時(shí)自動(dòng)調(diào)用該方法,此函數(shù)可以用于判斷是否需要從后端服務(wù)器取內(nèi)容。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
fetch:表示從后端獲取請(qǐng)求的內(nèi)容,并把控制權(quán)交給vcl_fetch函數(shù)。
error code [reason]
pass
(7)vcl_fetch函數(shù)
在從后端主機(jī)更新緩存并且獲取內(nèi)容后調(diào)用該方法,接著,通過(guò)判斷獲取的內(nèi)容來(lái)決定是否將內(nèi)容放入緩存,還是直接返回給客戶端。
此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
error code [reason]
pass
deliver
(8)vcl_deliver函數(shù)
在緩存中找到請(qǐng)求的內(nèi)容后,發(fā)送給客戶端前調(diào)用此方法。此函數(shù)一般以如下幾個(gè)關(guān)鍵字結(jié)束:
error code [reason]
deliver
(9)vcl_timeout 函數(shù)
此函數(shù)在緩存內(nèi)容到期前調(diào)用。一般以如下幾個(gè)關(guān)鍵字結(jié)束:
discard:表示從緩存中清除該內(nèi)容。
fetch
(10)vcl_discard函數(shù)
在緩存內(nèi)容到期后或緩存空間不夠時(shí),自動(dòng)調(diào)用該方法,一般以如下幾個(gè)關(guān)鍵字結(jié)束:
keep:表示將內(nèi)容繼續(xù)保留在緩存中。
discard
#p#
2、VCL處理流程圖
通過(guò)上面對(duì)VCL函數(shù)的介紹,讀者對(duì)各個(gè)函數(shù)實(shí)現(xiàn)的功能已經(jīng)有了一個(gè)了解,其實(shí)每個(gè)函數(shù)之間都是相互關(guān)聯(lián)的,下圖列出了varnish處理HTTP請(qǐng)求的一個(gè)運(yùn)行流程圖。
處理過(guò)程大致分為如下幾個(gè)步驟:
(1) Receive狀態(tài),也就是請(qǐng)求處理的入口狀態(tài),根據(jù)VCL規(guī)則判斷該請(qǐng)求應(yīng)該是Pass或Pipe,或者進(jìn)入Lookup(本地查詢)。
(2) Lookup狀態(tài),進(jìn)入此狀態(tài)后,會(huì)在hash表中查找數(shù)據(jù),若找到,則進(jìn)入Hit狀態(tài),否則進(jìn)入miss狀態(tài)。
(3) Pass狀態(tài),在此狀態(tài)下,會(huì)進(jìn)入后端請(qǐng)求,即進(jìn)入fetch狀態(tài)。
(4) Fetch狀態(tài),在Fetch狀態(tài)下,對(duì)請(qǐng)求進(jìn)行后端的獲取,發(fā)送請(qǐng)求,獲得數(shù)據(jù),并進(jìn)行本地的存儲(chǔ)。
(5) Deliver狀態(tài), 將獲取到的數(shù)據(jù)發(fā)送給客戶端,然后完成本次請(qǐng)求。
3、內(nèi)置公用變量
VCL內(nèi)置的公用變量可以用在不同的VCL函數(shù)中,根據(jù)這些公用變量使用的不同階段,下面依次介紹。
當(dāng)請(qǐng)求到達(dá)后,可以使用的公用變量如表2所示:
表2
公用變量名稱 含義
req.backend 指定對(duì)應(yīng)的后端主機(jī)
server.ip 表示服務(wù)器端IP
client.ip 表示客戶端IP
req.request 指定請(qǐng)求的類型,例如GET、HEAD、POST等
req.url 指定請(qǐng)求的地址
req.proto 表示客戶端發(fā)起請(qǐng)求的HTTP協(xié)議版本
req.http.header 表示對(duì)應(yīng)請(qǐng)求中的http頭部信息
req. restarts 表示請(qǐng)求重啟的次數(shù),默認(rèn)最大值為4
Varnish 在向后端主機(jī)請(qǐng)求時(shí),可以使用的公用變量如表3所示:
表3
公用變量名稱 含義
beresp.request 指定請(qǐng)求的類型,例如GET、HEAD等
beresp.url 指定請(qǐng)求的地址
beresp .proto 表示客戶端發(fā)起請(qǐng)求的HTTP協(xié)議版本
beresp .http.header 表示對(duì)應(yīng)請(qǐng)求中的http頭部信息
beresp .ttl 表示緩存的生存周期,也就是cache保留多長(zhǎng)時(shí)間,單位是秒
從cache或者后端主機(jī)獲取內(nèi)容后,可以使用的公用變量如表4所示:
表4
公用變量名稱 含義
obj.status 表示返回內(nèi)容的請(qǐng)求狀態(tài)代碼,例如200、302、504等
obj.cacheable 表示返回的內(nèi)容是否可以緩存,也就是說(shuō),如果HTTP返回是200、203、300、301、302、404、410等,并且有非0的生存期,則可以緩存
obj.valid 表示是否是有效的HTTP應(yīng)答
obj.response 表示返回內(nèi)容的請(qǐng)求狀態(tài)信息
obj.proto 表示返回內(nèi)容的HTTP協(xié)議版本
obj.ttl 表示返回內(nèi)容的生存周期,也就是緩存時(shí)間,單位是秒
obj.lastuse 表示返回上一次請(qǐng)求到現(xiàn)在的間隔時(shí)間,單位是秒
對(duì)客戶端應(yīng)答時(shí),可以使用的公用變量如表5所示:
表5
公用變量名稱 含義
resp.status 表示返回給客戶端的HTTP狀態(tài)代碼
resp.proto 表示返回給客戶端的HTTP協(xié)議版本
resp.http.header 表示返回給客戶端的HTTP頭部信息
resp.response 表示返回給客戶端的HTTP狀態(tài)信息
在上面的講述中,我們只是介紹了常用的VCL內(nèi)置公用變量,如果需要了解和使用更多的公用變量信息,請(qǐng)登錄varnish官方網(wǎng)站查閱。
#p#
三 、配置一個(gè)簡(jiǎn)單的Varnish實(shí)例
由于版本的不同,Varnish配置文件的寫法也存在一定差異,varnish2.x版本和1.x版本之間不但配置文件寫法不同,而且新的版本功能也增 加很多,并且去除了很多應(yīng)用BUG,這里講述的版本是varnish2.1.2,配置文件寫法也以varnish2.x版本為基準(zhǔn)。
Varnish安裝完成后,默認(rèn)的配置文件為/usr/local/varnish/etc/varnish/default.vcl,此文件內(nèi)容默認(rèn)全 部被注釋掉了,這里,我們以這個(gè)文件為模板,創(chuàng)建一個(gè)新的文件vcl.conf,并且放到/usr/local/varnish/etc目錄下,配置完成 的vcl.conf文件如下:
#通過(guò)backend定義了一個(gè)名稱為webserver的后端主機(jī),“.host”指定后端主機(jī)的IP地址或者域名,“.port”指定后端主機(jī)的服務(wù)端口。其中,“192.168.12.26”就是后端的一個(gè)web服務(wù)器。
backend webserver {
.host = "192.168.12.26";
.port = "80";
}
#調(diào)用vcl_recv開始。
sub vcl_recv {
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;
}
#如果請(qǐng)求的類型不是GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE時(shí),進(jìn)入pipe模式。注意這里是“&&”的關(guān)系。
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
return (pipe);
}
#如果請(qǐng)求的類型不是GET與HEAD,則進(jìn)入pass模式。
if (req.request != "GET" && req.request != "HEAD") {
return (pass);
}
#對(duì)ixdba.net或者ixdba.cn兩個(gè)域名進(jìn)行緩存加速,這是個(gè)泛域名的概念,也就是所有以ixdba.net或者ixdba.cn結(jié)尾的域名都進(jìn)行緩存。
if (req.http.host ~ "^(.*).ixdba.net" || req.http.host ~ "^(.*).ixdba.cn") {
set req.backend = webserver;
}
#對(duì)以.jsp和.do結(jié)尾以及帶有?的URL時(shí),直接從后端服務(wù)器讀取內(nèi)容。
if (req.url ~ "\.(jsp|do)($|\?)") {
return (pass);
} else {
return (lookup);
}
}
sub vcl_pipe {
return (pipe);
}
sub vcl_pass {
return (pass);
}
sub vcl_hash {
set req.hash += req.url;
if (req.http.host) {
set req.hash += req.http.host;
} else {
set req.hash += server.ip;
}
return (hash);
}
sub vcl_hit {
if (!obj.cacheable) {
return (pass);
}
return (deliver);
}
sub vcl_miss {
return (fetch);
}
sub vcl_fetch {
if (!beresp.cacheable) {
return (pass);
}
if (beresp.http.Set-Cookie) {
return (pass);
}
#當(dāng)url中包含servlet時(shí),不進(jìn)行緩存。
if (req.url ~ "^/servlet/") {
return (pass);
}
#當(dāng)url中包含services時(shí),不進(jìn)行緩存。
if (req.url ~ "^/services/") {
return (pass);
}
#對(duì)于請(qǐng)求類型是GET,并且請(qǐng)求的URL中包含upload,那么就進(jìn)行緩存,緩存的時(shí)間是300秒,即5分鐘。
if (req.request == "GET" && req.url ~ "^/upload(.*)$") {
set beresp.ttl = 300s;
}
#對(duì)于請(qǐng)求類型是GET,并且請(qǐng)求的URL以png、xsl、xml、gif、css、js等結(jié)尾時(shí),則進(jìn)行緩存,緩存時(shí)間為600秒。
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); }
#下面是添加一個(gè)Header標(biāo)識(shí),以判斷緩存是否命中。
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from www.ixdba.net";
} else {
set resp.http.X-Cache = "MISS from www.ixdba.net";
}
return (deliver);
}