實驗目的:
varnish利用實作對後端單雙靜态web伺服器的緩存
varnish包的下載下傳路徑:http://repo.varnish-cache.org/redhat/varnish-3.0/el6 可以下載下傳到varnish的rpm包
需要下載下傳的有:
varnish-3.0.5-1.el6.x86_64
varnish-docs-3.0.5-1.el6.x86_64
varnish-libs-3.0.5-1.el6.x86_64
varnish的官網位址:https://www.varnish-cache.org/
實驗環境:
web1:172.16.18.3 Nginx
web2:172.16.17.12 Nginx
varnish:172.16.18.1 Varnish
實驗内容:
一,安裝varnish包,配置web伺服器
[root@node1~]# rpm -ql varnish
/etc/rc.d/init.d/varnish #varnish的啟動程式
/etc/rc.d/init.d/varnishlog #日志
/etc/rc.d/init.d/varnishncsa #日志
/etc/sysconfig/varnish #配置檔案,varnish定義自身屬性
/etc/varnish #配置檔案目錄
/etc/varnish/default.vcl #預設配置檔案,定義後端節點的
/usr/bin/varnish_reload_vcl #加載vcl,
/usr/bin/varnishadm #用戶端程式
/usr/bin/varnishstat #狀态監控
二,編輯配置檔案
[root@node1 ~]# vim /etc/sysconfig/varnish
NFILES=131072
MEMLOCK=82000
NPROCS="unlimited"
RELOAD_VCL=1 #是否重載VCL檔案
## Alternative 3, Advanced configuration
VARNISH_VCL_CONF=/etc/varnish/default.vcl #vcl檔案路徑
VARNISH_LISTEN_PORT=80 #varnish自己工作于那個端口。預設是6081
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 #管理接口
VARNISH_ADMIN_LISTEN_PORT=6082 #管理接口監聽端口
VARNISH_SECRET_FILE=/etc/varnish/secret #密鑰檔案
VARNISH_MIN_THREADS=50 #最少空閑線程
VARNISH_MAX_THREADS=1000 #最多啟動線程
VARNISH_THREAD_TIMEOUT=120 #work逾時時長
#VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin #存儲檔案
VARNISH_STORAGE_SIZE=64M #存儲檔案檔案大小
#VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" #存儲方式file
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" #基于記憶體方式
VARNISH_TTL=120
DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
-f ${VARNISH_VCL_CONF} \
-T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
-t ${VARNISH_TTL} \
-w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
-u varnish -g varnish \
-S ${VARNISH_SECRET_FILE} \
-s ${VARNISH_STORAGE}"
[root@node1 ~]# vim /etc/varnish/default.vcl
backend default {
.host = "172.16.18.3";
.port = "80";
}
此時varnish就已經可以啟動了。下來就是最重要的編寫vcl檔案。
那麼我們就應該熟悉這張表,每一個狀态引擎所對應的變量

簡單介紹一下vcl的文法
VCL的設計參考了C和Perl語言,是以,對有着C或Perl程式設計經驗者來說,其非常易于了解。其基本文法說明如下:
(1)//、#或/* comment */用于注釋
(2)sub $name 定義函數
(3)不支援循環,有内置變量
(4)使用終止語句,沒有傳回值
(5)域專用
(6)操作符:=(指派)、==(等值比較)、~(模式比對)、!(取反)、&&(邏輯與)、||(邏輯或)
編譯vcl檔案中狀态引擎的順序我們按照預設配置檔案的順序來,此順序也符合請求處理的基本順序,當然,為了配合實驗也會有些改動。我們來看一張圖,可以明确的明白請求的過程:
1,首先我們來編寫vcl_recv段,
vcl_recv作為進入varnish對請求封包解碼後第一個子例程,可以在此處做通路控制,是否查詢緩存,以及無法識别的資料的判定。
首先對default.vcl檔案複制一份重新改名為test1.vcl
acl purgers { #定義一個acl
"127.0.0.1";
"172.16.0.0"/16;
}
sub vcl_recv {
if (req.url ~ "^/test.html$") { #請求首部的url比對到test.html,
return(pass); #跳過緩存
}
if
if (req.request != "GET" && #請求方法不是已知的這7中則發到pipe上去
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") { #不是擷取資源的全部跳過緩存,減少無用緩存查詢
return (pass);
}
if (req.request == "PURGE") {
if (!client.ip ~ purgers) { #請求IP不在ACL中定義,則發揮405錯誤頁。
error 405 "Method not allowed";
}
return (lookup);
}
return (lookup);
那麼此時如何加載這個test1讓他生效呢?
第一修改配置檔案。
第二,利用varnishadm用戶端工具。
varnishadm
[root@node1 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 #進入到管理工具
200
-----------------------------
Varnish Cache CLI 1.0
Linux,2.6.32-431.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit
varnish-3.0.5 revision 1a89b1f
Type 'help' for command list.
Type 'quit' to close CLI session.
varnish> vcl.load test1 test1.vcl #加載vcl檔案
200
VCL compiled.
varnish> vcl.list
active 2 boot
available 0 test1
varnish> vcl.use test1
available 2 boot
active 0 test1
這樣就設定成功了。
為了顯示效果我們來配置一下deliver段,給用戶端傳回時候比對到緩存資訊,以便我我們來檢視實驗結果。
sub vcl_deliver {
if (obj.hits > 0) { #判斷條件緩存比對次數大于0
set resp.http.X-Cache = "HIT via" + " " + server.hostname; #添加HIT via
} else {
set resp.http.X-Cache = "MISS via" + " " + server.hostname; #沒有比對到則添加MISS via
通路緩存172.16.18.1.第一次是miss via 之後的通路在緩存有效期内都是HIT via
當通路test.html是會被vcl_recv定義的pass比對到,直接跳過緩存,是以X-cache狀态一直是MISS via
2,編輯vcl_hash,自定義hash生成時的資料來源。
sub vcl_hash {
hash_data(req.url); #依據req.url來比對
if (req.http.host) {
hash_data(req.http.host); #請求首部的host來緩存
} else {
hash_data(server.ip);
}
return (hash);
3,編輯vcl_hit,從緩存中查找到緩存對象時要執行的操作
sub vcl_hit {
if(req.request == "PURGE"){ #當進入緩存後清理緩存對象,傳回Purged;
purge;
error 200 "Purged";
非pipe請求必經過hit,miss,pass,這三條任意一條,是以也要在其他兩路做purge比對。
4,vcl_miss ,從緩存中查找不到緩存對象時要執行的操作;
sub vcl_miss {
if (req.request == "PURGE") { 如果直接不經過緩存,比對到了PURGE,則傳回404說沒有進入緩存,否則發往fetch
error 404 "Not in cache";
return (fetch);
5,vcl_pass,用于将請求直接傳遞至後端主機
vcl_pass {
if (req.request == "PURGE") { #如果直接是pass,跳過緩存,且比對到PURGE,
error 502 "PURGE on a passed object";
return (pass);
6,vcl_fetch,是在請求從後端被成功接收後調用的,可以使用req,bereq,beresp.
可在此處定義cache的緩存有效時長
sub vcl_fetch {
set beresp.ttl = 360s; #修改緩存時長為360s,
if (req.url ~ ".[jpg|gif|png]$"){ #圖檔檔案緩存時長1h
set beresp.ttl = 1h;
if (beresp.status != 200){ #backend傳回狀态碼不是200,則不緩存資料
return (hit_for_pass);
return (deliver);
6,sub vcl_deliver ,将使用者請求的内容響應給用戶端時用到的方法;deliver,在recv之後我們就用過,在裡邊添加了一個相應給使用者的X-cache,是否用到了緩存。複制下來!完善一下!
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT via" + " " + server.hostname;
set resp.http.X-Cache = "MISS via" + " " + server.hostname;
set resp.http.host = server.hostname;
retuen (deliver);
7,sub vcl_pipe {
return (pipe);
到此一個簡單的vcl功能就寫好了。
先請求一下curl -X PURGE http://172.16.18.1/index.html
[root@node3 html]# curl -X PURGE http://172.16.18.1/index.html
<html>
<head><title>405 Not Allowed</title></head> #發現和我們定義的Method not allowed不一樣,那是為什麼呢?
<body bgcolor="white">
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.6.2</center>
</body>
</html>
經過檢視vcl_recv段發現,我們在PURGE之上就将不是定義的方法送到了pipe.無法到達PURGE.修改如下。将PURGE寫在方法判斷之前
if (req.url ~ "^/test.html$") {
return(pass);
if (!client.ip ~ purgers) {
if (req.request != "GET" &&
if (req.request != "GET" && req.request != "HEAD") {
<?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">
<head>
<title>404 Not in cache</title>
</head>
<body>
<h1>Error 404 Not in cache</h1>
Not in cache
<h3>Guru Meditation:</h3>
XID: 506876240
<hr>
Varnish cache server
這下和我們定義的一樣的,看來還得注意判斷的先後次序。
下邊我們來定義一下有cookie的檔案走向。
首先在vcl_resv添加
if (!(req.url ~ "wp-(login|admin)")) { #所有有cookie的請求都不查緩存
unset req.http.cookie;
}
在vcl_fetch中定義抹除cookie
if (!(req.url ~ "wp-(login|admin)")) {
unset beresp.http.Set-Cookie;
三,後端主機的健康檢測
backend web1 {
.host = "172.16.18.3";
.port = "80";
.probe = {
.url = "/index.html"; #探測什麼檔案
.interval = 1s; #幾秒探測一次
.window = 5; #失敗探測多少次
.threshold = 2; #成功探測多少次
在varnishadm中檢視
varnish> backend.list
Backend name Refs Admin Probe
default(172.16.18.3,,80) 8 probe Healthy 5/5
四,varnish使用多台後端主機
Varnish中可以使用director指令将一個或多個近似的後端主機定義為一個邏輯組,并可以指定的排程方式(也叫挑選方法)來輪流将請求發送至這些主機上。不同的director可以使用同一個後端主機,而某director也可以使用“匿名”後端主機(在director中直接進行定義)。每個director都必須有其專用名,且在定義後必須在VCL中進行調用,VCL中任何可以指定後端主機的位置均可以按需将其替換為調用某已定義的director。
注意:當使用自定義的主機時一定要在vcl_recv中指定使用哪個主機,
.url = "/index.html";
.interval = 1s;
.window = 5;
.threshold = 2;
backend web2 {
.url = "/index.html";
.interval = 1s;
.window = 5;
director webservers round-robin {
{.backend = web1;}
{.backend = web2;}
vcl_recv { 添加下邊段落
set req.backend = webservers; 放在最前邊
下來通路172.16.18.1驗證有沒有将請求在兩個web伺服器上輪詢,