Linux varnish4.0緩存代理配置

2018-07-31 14:45 更新

防偽碼:你必須非常努力,才能看起來(lái)毫不費(fèi)力。

一、varnish原理:

1)Varnish簡(jiǎn)介:

varnish緩存是web應(yīng)用加速器,同時(shí)也作為http反向緩存代理。你可以安裝varnish在任何http的前端,同時(shí)配置它緩存內(nèi)容。與傳統(tǒng)的 squid 相比,varnish 具有性能更高、速度更快、管理更加方便等諸多優(yōu)點(diǎn)。有一部分企業(yè)已經(jīng)在生產(chǎn)環(huán)境中使用其作為舊版本的squid的替代方案,以在相同的服務(wù)器成本下提供更好的緩存效果,Varnish更是作為CDN緩存服務(wù)器的可選服務(wù)之一。

根據(jù)官網(wǎng)的介紹,Varnish的主要特性如下:https://www.varnish-cache.org/

1.緩存位置:可以使用內(nèi)存也可以使用磁盤(pán)。如果要使用磁盤(pán)的話(huà)推薦SSD做RAID1

2.日志存儲(chǔ):日志也存儲(chǔ)在內(nèi)存中。存儲(chǔ)策略:固定大小,循環(huán)使用

3.支持虛擬內(nèi)存的使用。

4.有精確的時(shí)間管理機(jī)制,即緩存的時(shí)間屬性控制。

5.狀態(tài)引擎架構(gòu):在不同的引擎上完成對(duì)不同的緩存和代理數(shù)據(jù)進(jìn)行處理??梢酝ㄟ^(guò)特定的配置語(yǔ)言設(shè)計(jì)不同的控制語(yǔ)句,以決定數(shù)據(jù)在不同位置以不同方式緩存,在特定的地方對(duì)經(jīng)過(guò)的報(bào)文進(jìn)行特定規(guī)則的處理。

6.緩存管理:以二叉堆格式管理緩存數(shù)據(jù),做到數(shù)據(jù)的及時(shí)清理。

2)Varnish與Squid的對(duì)比

相同點(diǎn):

都是一個(gè)反向代理服務(wù)器;

都是開(kāi)源軟件;

Varnish的優(yōu)勢(shì):

1、Varnish的穩(wěn)定性很高,兩者在完成相同負(fù)荷的工作時(shí),Squid服務(wù)器發(fā)生故障的幾率要高于Varnish,因?yàn)槭褂肧quid要經(jīng)常重啟;

2、Varnish訪(fǎng)問(wèn)速度更快,因?yàn)椴捎昧恕癡isual Page Cache”技術(shù),所有緩存數(shù)據(jù)都直接從內(nèi)存讀取,而squid是從硬盤(pán)讀取,因而Varnish在訪(fǎng)問(wèn)速度方面會(huì)更快;

3、Varnish可以支持更多的并發(fā)連接,因?yàn)閂arnish的TCP連接釋放要比Squid快,因而在高并發(fā)連接情況下可以支持更多TCP連接;

4、Varnish可以通過(guò)管理端口,使用正則表達(dá)式批量的清除部分緩存,而Squid是做不到的;

squid屬于是單進(jìn)程使用單核CPU,但Varnish是通過(guò)fork形式打開(kāi)多進(jìn)程來(lái)做處理,所以可以合理的使用所有核來(lái)處理相應(yīng)的請(qǐng)求;

Varnish的劣勢(shì):

1、varnish進(jìn)程一旦Crash或者重啟,緩存數(shù)據(jù)都會(huì)從內(nèi)存中完全釋放,此時(shí)所有請(qǐng)求都會(huì)發(fā)送到后端服務(wù)器,在高并發(fā)情況下,會(huì)給后端服務(wù)器造成很大壓力;

2、在varnish使用中如果單個(gè)url的請(qǐng)求通過(guò)HA/F5等負(fù)載均衡,則每次請(qǐng)求落在不同的varnish服務(wù)器中,造成請(qǐng)求都會(huì)被穿透到后端;而且同樣的請(qǐng)求在多臺(tái)服務(wù)器上緩存,也會(huì)造成varnish的緩存的資源浪費(fèi),造成性能下降;

Varnish劣勢(shì)的解決方案:

針對(duì)劣勢(shì)一:在訪(fǎng)問(wèn)量很大的情況下推薦使用varnish的內(nèi)存緩存方式啟動(dòng),而且后面需要跟多臺(tái)squid/nginx服務(wù)器。主要為了防止前面的varnish服 務(wù)、服務(wù)器被重啟的情況下,大量請(qǐng)求穿透varnish,這樣squid/nginx可以就擔(dān)當(dāng)?shù)诙覥ACHE,而且也彌補(bǔ)了varnish緩存在內(nèi)存中重啟都會(huì)釋放的問(wèn)題;

針對(duì)劣勢(shì)二:可以在負(fù)載均衡上做url哈希,讓單個(gè)url請(qǐng)求固定請(qǐng)求到一臺(tái)varnish服務(wù)器上;

3)使用varnish作為web代理緩存的原理 :

varnish是一個(gè)http反向代理的緩存。它從客戶(hù)端接收請(qǐng)求然后嘗試從緩存中獲取數(shù)據(jù)來(lái)響應(yīng)客戶(hù)端的請(qǐng)求,如果varnish不能從緩存中獲得數(shù)據(jù)來(lái)響應(yīng)客戶(hù)端,它將轉(zhuǎn)發(fā)請(qǐng)求到后端(backend servers),獲取響應(yīng)同時(shí)存儲(chǔ),最后交付給客戶(hù)端。 

如果varnish已經(jīng)緩存了某個(gè)響應(yīng),它比你傳統(tǒng)的后端服務(wù)器的響應(yīng)要快很多,所以你需要盡可能是更多的請(qǐng)求直接從varnish的緩存中獲取響應(yīng)。 

varnish決定是緩存內(nèi)容或者是從后端服務(wù)器獲取響應(yīng)。后端服務(wù)器能通過(guò)http響應(yīng)頭中的Cache-Control來(lái)同步varnish緩存內(nèi)容。在某些條件下varnish將不緩存內(nèi)容,最常見(jiàn)的是使用cookie。當(dāng)一個(gè)被標(biāo)記有cookie的客戶(hù)端web請(qǐng)求,varnish默認(rèn)是不緩存。這些眾多的varnish功能特點(diǎn)都是可以通過(guò)寫(xiě)vcl來(lái)改變的。

5)簡(jiǎn)單架構(gòu):

Varnish 分為 management 進(jìn)程和child 進(jìn)程;

Management進(jìn)程:對(duì)子進(jìn)程進(jìn)行管理,同時(shí)對(duì)VCL配置進(jìn)行編譯,并應(yīng)用到不同的狀態(tài)引擎。

Child進(jìn)程:生成線(xiàn)程池,負(fù)責(zé)對(duì)用戶(hù)請(qǐng)求進(jìn)行處理,并通過(guò)hash查找返回用戶(hù)結(jié)果。

6)varnish主要配置部分:

varnish配置主要分為:后端配置,ACL配置,probes配置,directors配置,核心子程序配置幾大塊。其中后端配置是必要的,在多臺(tái)服務(wù)器中還會(huì)用到directors配置,核心子程序配置。

后端配置:即給varnish添加反代服務(wù)器節(jié)點(diǎn),最少配置一個(gè)。

ACL配置:即給varnish添加訪(fǎng)問(wèn)控制列表,可以指定這些列表訪(fǎng)問(wèn)或禁止訪(fǎng)問(wèn)。

probes配置:即給varnish添加探測(cè)后端服務(wù)器是否正常的規(guī)則,方便切換或禁止對(duì)應(yīng)后端服務(wù)器。

directors配置:即給varnish添加負(fù)載均衡模式管理多個(gè)后端服務(wù)器。

核心子程序配置:即給varnish添加后端服務(wù)器切換,請(qǐng)求緩存,訪(fǎng)問(wèn)控制,錯(cuò)誤處理等規(guī)則。

7)VCL中內(nèi)置預(yù)設(shè)變量:變量(也叫object):

1
2
3
4
5
6
7
8
eq:The request object,請(qǐng)求到達(dá)時(shí)可用的變量(客戶(hù)端發(fā)送的請(qǐng)求對(duì)象)
bereq:The backend request object,向后端主機(jī)請(qǐng)求時(shí)可用的變量
beresp:The backend response object,從后端主機(jī)獲取內(nèi)容時(shí)可用的變量(后端響應(yīng)請(qǐng)求對(duì)象)
resp:The HTTP response object,對(duì)客戶(hù)端響應(yīng)時(shí)可用的變量(返回給客戶(hù)端的響應(yīng)對(duì)象)
obj:存儲(chǔ)在內(nèi)存中時(shí)對(duì)象屬性相關(guān)的可用的變量(高速緩存對(duì)象,緩存后端響應(yīng)請(qǐng)求內(nèi)容)
預(yù)設(shè)變量是系統(tǒng)固定的,請(qǐng)求進(jìn)入對(duì)應(yīng)的vcl子程序后便生成,這些變量可以方便子程序提取,當(dāng)然也可以自定義一些全局變量。
當(dāng)前時(shí)間:
now :作用:返回當(dāng)前時(shí)間戳。
1
2
3
4
客戶(hù)端:(客戶(hù)端基本信息)
client.ip:返回客戶(hù)端IP地址。
注:原client.port已經(jīng)棄用,如果要取客戶(hù)端請(qǐng)求端口號(hào)使用 std.port(client.ip),需要import std;才可以使用std
client.identity:用于裝載客戶(hù)端標(biāo)識(shí)碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
服務(wù)器:(服務(wù)器基本信息)
注:原server.port已經(jīng)棄用,如果要取服務(wù)器端口號(hào)使用 std.port(server.ip),需要import std;才可以使用std
server.hostname:服務(wù)器主機(jī)名。
server.identity:服務(wù)器身份標(biāo)識(shí)。
server.ip:返回服務(wù)器端IP地址。
  
req :(客戶(hù)端發(fā)送的請(qǐng)求對(duì)象)
req:整個(gè)HTTP請(qǐng)求數(shù)據(jù)結(jié)構(gòu)
req.backend_hint:指定請(qǐng)求后端節(jié)點(diǎn),設(shè)置后 bereq.backend 才能獲取后端節(jié)點(diǎn)配置數(shù)據(jù)
req.can_gzip:客戶(hù)端是否接受GZIP傳輸編碼。
req.hash_always_miss:是否強(qiáng)制不命中高速緩存,如果設(shè)置為true,則高速緩存不會(huì)命中,一直會(huì)從后端獲取新數(shù)據(jù)。
req.hash_ignore_busy:忽略緩存中忙碌的對(duì)象,多臺(tái)緩存時(shí)可以避免死鎖。
req.http:對(duì)應(yīng)請(qǐng)求HTTP的header。
req.method:請(qǐng)求類(lèi)型(如 GET , POST)。
req.proto:客戶(hù)端使用的HTTP協(xié)議版本。
req.restarts:重新啟動(dòng)次數(shù)。默認(rèn)最大值是4
req.ttl:緩存有剩余時(shí)間。
req.url:請(qǐng)求的URL。
req.xid:唯一ID。
  
bereq:(發(fā)送到后端的請(qǐng)求對(duì)象,基于req對(duì)象)
bereq:整個(gè)后端請(qǐng)求后數(shù)據(jù)結(jié)構(gòu)。
bereq.backend:所請(qǐng)求后端節(jié)點(diǎn)配置。
bereq.between_bytes_timeout:從后端每接收一個(gè)字節(jié)之間的等待時(shí)間(秒)。
bereq.connect_timeout:連接后端等待時(shí)間(秒),最大等待時(shí)間。
bereq.first_byte_timeout:等待后端第一個(gè)字節(jié)時(shí)間(秒),最大等待時(shí)間。
bereq.http:對(duì)應(yīng)發(fā)送到后端HTTP的header信息。
bereq.method:發(fā)送到后端的請(qǐng)求類(lèi)型(如:GET , POST)。
bereq.proto:發(fā)送到后端的請(qǐng)求的HTTP版本。
bereq.retries:相同請(qǐng)求重試計(jì)數(shù)。
bereq.uncacheable:無(wú)緩存這個(gè)請(qǐng)求。
bereq.url:發(fā)送到后端請(qǐng)求的URL。
bereq.xid:請(qǐng)求唯一ID。
  
beresp:(后端響應(yīng)請(qǐng)求對(duì)象)
beresp:整個(gè)后端響應(yīng)HTTP數(shù)據(jù)結(jié)構(gòu)。
beresp.backend.ip:后端響應(yīng)的IP。
beresp.backend.name:響應(yīng)后端配置節(jié)點(diǎn)的name。
beresp.do_gunzip:默認(rèn)為 false 。緩存前解壓該對(duì)象
beresp.do_gzip:默認(rèn)為 false 。緩存前壓縮該對(duì)象
beresp.grace:設(shè)置當(dāng)前對(duì)象緩存過(guò)期后可額外寬限時(shí)間,用于特殊請(qǐng)求加大緩存時(shí)間,當(dāng)并發(fā)量巨大時(shí),不易設(shè)置過(guò)大否則會(huì)堵塞緩存,一般可設(shè)置 1m 左右,當(dāng)beresp.ttl=0s時(shí)該值無(wú)效。
beresp.http:對(duì)應(yīng)的HTTP請(qǐng)求header
beresp.keep:對(duì)象緩存后帶保持時(shí)間
beresp.proto:響應(yīng)的HTTP版本beresp.reason:由服務(wù)器返回的HTTP狀態(tài)信息
beresp.status:由服務(wù)器返回的狀態(tài)碼
beresp.storage_hint:指定保存的特定存儲(chǔ)器
beresp.ttl:該對(duì)象緩存的剩余時(shí)間,指定統(tǒng)一緩存剩余時(shí)間。
beresp.uncacheable:繼承bereq.uncacheable,是否不緩存
  
OBJ :(高速緩存對(duì)象,緩存后端響應(yīng)請(qǐng)求內(nèi)容)
obj.grace:該對(duì)象額外寬限時(shí)間
obj.hits:緩存命中次數(shù),計(jì)數(shù)器從1開(kāi)始,當(dāng)對(duì)象緩存該值為1,一般可以用于判斷是否有緩存,當(dāng)前該值大于0時(shí)則為有緩存。
obj.http:對(duì)應(yīng)HTTP的header
obj.proto:HTTP版本
obj.reason:服務(wù)器返回的HTTP狀態(tài)信息
obj.status:服務(wù)器返回的狀態(tài)碼
obj.ttl:該對(duì)象緩存剩余時(shí)間(秒)
obj.uncacheable:不緩存對(duì)象
  
resp :(返回給客戶(hù)端的響應(yīng)對(duì)象)
resp:整個(gè)響應(yīng)HTTP數(shù)據(jù)結(jié)構(gòu)。
resp.http:對(duì)應(yīng)HTTP的header。
resp.proto:編輯響應(yīng)的HTTP協(xié)議版本。
resp.reason:將要返回的HTTP狀態(tài)信息。
resq.status:將要返回的HTTP狀態(tài)碼。
  
存儲(chǔ) :
storage.<name>.free_space:存儲(chǔ)可用空間(字節(jié)數(shù))。
storage.<name>.used_space:存儲(chǔ)已經(jīng)使用空間(字節(jié)數(shù))。
storage.<name>.happy:存儲(chǔ)健康狀態(tài)。

8、特定功能性語(yǔ)句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ban(expression):清除指定對(duì)象緩存
call(subroutine):調(diào)用子程序,如:call(name);
hash_data(input):生成hash鍵,用于制定hash鍵值生成結(jié)構(gòu),只能在vcl_hash子程序中使用。調(diào)用 hash_data(input) 后,即這個(gè)hash為當(dāng)前頁(yè)面的緩存hash鍵值,無(wú)需其它獲取或操作,如:
sub vcl_hash{
       hash_data(client.ip);
       return(lookup);
}
注意:return(lookup); 是默認(rèn)返回值,所以可以不寫(xiě)。
new():創(chuàng)建一個(gè)vcl對(duì)象,只能在vcl_init子程序中使用。
return():結(jié)束當(dāng)前子程序,并指定繼續(xù)下一步動(dòng)作,如:return (ok); 每個(gè)子程序可指定的動(dòng)作均有不同。
rollback():恢復(fù)HTTP頭到原來(lái)狀態(tài),已經(jīng)棄用,使用 std.rollback() 代替。
synthetic(STRING):合成器,用于自定義一個(gè)響應(yīng)內(nèi)容,比如當(dāng)請(qǐng)求出錯(cuò)時(shí),可以返回自定義 404 內(nèi)容,而不只是默認(rèn)頭信息,只能在 vcl_synth 與 vcl_backend_error 子程序中使用,如:
sub vcl_synth {
    //自定義內(nèi)容
    synthetic ({"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="zh-cn">
   <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
      <title>error</title>
   </head>
   <body>
      <h1>Error</h1>
      <h3>這只是一個(gè)測(cè)試自定義響應(yīng)異常內(nèi)容</h3>
   </body>
</html>
    "});
    //只交付自定義內(nèi)容
    return(deliver);
  
regsub(str, regex, sub):使用正則替換第一次出現(xiàn)的字符串,第一個(gè)參數(shù)為待處理字符串,第二個(gè)參數(shù)為正則表達(dá)式,第三個(gè)為替換為字符串。
regsuball(str, regex, sub):使用正則替換所有匹配字符串。參數(shù)與regsuball相同。
具體變量詳見(jiàn):
https://www.varnish-cache.org/docs/4.0/reference/vcl.html#reference-vcl

(9)return 語(yǔ)句:

return 語(yǔ)句是終止子程序并返回動(dòng)作,所有動(dòng)作都根據(jù)不同的vcl子程序限定來(lái)選用。

https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html

語(yǔ)法:return(action);

常用的動(dòng)作:

1
2
3
4
5
6
7
8
9
10
11
12
abandon  放棄處理,并生成一個(gè)錯(cuò)誤。
deliver  交付處理
fetch  從后端取出響應(yīng)對(duì)象
hash  哈希緩存處理
lookup 查找緩存對(duì)象
ok 繼續(xù)執(zhí)行
pass  進(jìn)入pass非緩存模式
pipe 進(jìn)入pipe非緩存模式
purge 清除緩存對(duì)象,構(gòu)建響應(yīng)
restart 重新開(kāi)始
retry 重試后端處理
synth(status code,reason) 合成返回客戶(hù)端狀態(tài)信息

10)varnish中內(nèi)置子程序有:

注:varnish內(nèi)置子程序均有自己限定的返回動(dòng)作  return (動(dòng)作);  不同的動(dòng)作將調(diào)用對(duì)應(yīng)下一個(gè)子程序。

vcl_recv子程序:

開(kāi)始處理請(qǐng)求,通過(guò) return (動(dòng)作); 選擇varnish處理模式,默認(rèn)進(jìn)入hash緩存模式(即return(hash);),緩存時(shí)間為配置項(xiàng)default_ttl(默認(rèn)為 120秒)過(guò)期保持時(shí)間default_grace(默認(rèn)為10秒)。該子程序一般用于模式選擇,請(qǐng)求對(duì)象緩存及信息修改,后端節(jié)點(diǎn)修改,終止請(qǐng)求等操作。

可操作對(duì)象:(部分或全部值)

1
2
3
4
5
6
7
8
讀:client,server,req,storage
寫(xiě):client,req
返回值:
synth(status code,reason);  定義響應(yīng)內(nèi)容。
pass  進(jìn)入pass模式,并進(jìn)入vcl_pass子程序。
pipe  進(jìn)入pipe模式,并進(jìn)入vcl_pipe子程序。
hash  進(jìn)入hash緩存模式,并進(jìn)入vcl_hash子程序,默認(rèn)返回值。
purge  清除緩存等數(shù)據(jù),子程序先從vcl_hash再到vcl_purge。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
vcl_pipe子程序:
pipe模式處理,該模式主要用于直接取后端響應(yīng)內(nèi)容返回客戶(hù)端,可定義響應(yīng)內(nèi)容返回客戶(hù)端。該子程序一般用于需要及時(shí)且不作處理的后端信息,取出后端響應(yīng)內(nèi)容后直接交付到客戶(hù)端不進(jìn)入vcl_deliver子程序處理。
可操作對(duì)象:(部分或全部值)
讀:client,server,bereq,req,storage
寫(xiě):client,bereq,req
返回值:
synth(status code,reason);  定義響應(yīng)內(nèi)容。
pipe  繼續(xù)pipe模式,進(jìn)入后端vcl_backend_fetch子程序,默認(rèn)返回值。
  
vcl_pass子程序:
pass模式處理,該模式類(lèi)似hash緩存模式,僅不做緩存處理。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,storage
寫(xiě):client,req
返回值:
synth(status code,reason);  定義響應(yīng)內(nèi)容。
fetch  繼續(xù)pass模式,進(jìn)入后端vcl_backend_fetch子程序,默認(rèn)返回值。
  
vcl_hit子程序:
hash緩存模式時(shí),存在hash緩存時(shí)調(diào)用,用于緩存處理,可放棄或修改緩存。
可操作對(duì)象:(部分或全部值)
讀:client,server,obj,req,storage
寫(xiě):client,req
返回值:
restart 重啟請(qǐng)求。
deliver 交付緩存內(nèi)容,進(jìn)入vcl_deliver子程序處理,默認(rèn)返回值。
synth(status code,reason);  定義響應(yīng)內(nèi)容。
  
vcl_miss子程序:
hash緩存模式時(shí),不存在hash緩存時(shí)調(diào)用,用于判斷性的選擇進(jìn)入后端取響應(yīng)內(nèi)容,可以修改為pass模式。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,storage
寫(xiě):client,req
返回值:
restart 重啟請(qǐng)求。
synth(status code,reason);  定義響應(yīng)內(nèi)容。
pass 切換到pass模式,進(jìn)入vcl_pass子程序。
fetch  正常取后端內(nèi)容再緩存,進(jìn)入vcl_backend_fetch子程序,默認(rèn)返回值。
  
vcl_hash子程序:
hash緩存模式,生成hash值作為緩存查找鍵名提取緩存內(nèi)容,主要用于緩存hash鍵值處理,可使用hash_data(string) 指定鍵值組成結(jié)構(gòu),可在同一個(gè)頁(yè)面通過(guò)IP或cookie生成不同的緩存鍵值。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,storage
寫(xiě):client,req
返回值:
lookup 查找緩存對(duì)象,存在緩存進(jìn)入vcl_hit子程序,不存在緩存進(jìn)入vcl_miss子程序,當(dāng)使用了purge清理模式時(shí)會(huì)進(jìn)入vcl_purge子程序,默認(rèn)返回值。
  
vcl_purge子程序:
清理模式,當(dāng)查找到對(duì)應(yīng)的緩存時(shí)清除并調(diào)用,用于請(qǐng)求方法清除緩存,并報(bào)告。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,storage
寫(xiě):client,req
返回值:
synth(status code,reason);  定義響應(yīng)內(nèi)容。
restart 重啟請(qǐng)求。
  
vcl_deliver子程序:
客戶(hù)端交付子程序,在vcl_backend_response子程序后調(diào)用(非pipe模式),或vcl_hit子程序后調(diào)用,可用于追加響應(yīng)頭信息,cookie等內(nèi)容。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,resp,obj,storage
寫(xiě):client,req,resp
返回值:
deliver 正常交付后端或緩存響應(yīng)內(nèi)容,默認(rèn)返回值。
restart 重啟請(qǐng)求。
  
vcl_backend_fetch子程序:
發(fā)送后端請(qǐng)求之前調(diào)用,可用于改變請(qǐng)求地址或其它信息,或放棄請(qǐng)求。
可操作對(duì)象:(部分或全部值)
讀:server,bereq,storage
寫(xiě):bereq
返回值:
fetch 正常發(fā)送請(qǐng)求到到后端取出響應(yīng)內(nèi)容,進(jìn)入vcl_backend_response子程序,默認(rèn)返回值。
abandon 放棄后端請(qǐng)求,并生成一個(gè)錯(cuò)誤,進(jìn)入vcl_backend_error子程序。
  
vcl_backend_response子程序:
后端響應(yīng)后調(diào)用,可用于修改緩存時(shí)間及緩存相關(guān)信息。
可操作對(duì)象:(部分或全部值)
讀:server,bereq,beresp,storage
寫(xiě):bereq,beresp
返回值:
deliver 正常交付后端響應(yīng)內(nèi)容,進(jìn)入vcl_deliver子程序,默認(rèn)返回值。
abandon 放棄后端請(qǐng)求,并生成一個(gè)錯(cuò)誤,進(jìn)入vcl_backend_error子程序。
retry 重試后端請(qǐng)求,重試計(jì)數(shù)器加1,當(dāng)超過(guò)配置中max_retries值時(shí)會(huì)報(bào)錯(cuò)并進(jìn)入vcl_backend_error子程序。
  
vcl_backend_error子程序:
后端處理失敗調(diào)用,異常頁(yè)面展示效果處理,可自定義錯(cuò)誤響應(yīng)內(nèi)容,或修改beresp.status與beresp.http.Location重定向等。
可操作對(duì)象:(部分或全部值)
讀:server,bereq,beresp,storage
寫(xiě):bereq,beresp
返回值:
deliver 只交付 sysnthetic(string) 自定義內(nèi)容,默認(rèn)返回后端異常標(biāo)準(zhǔn)錯(cuò)誤內(nèi)容。
retry 重試后端請(qǐng)求,重試計(jì)數(shù)器加1,當(dāng)超過(guò)配置中max_retries值時(shí)會(huì)報(bào)錯(cuò)并進(jìn)入vcl_backend_error子程序。
  
vcl_synth子程序:
自定義響應(yīng)內(nèi)容??梢酝ㄟ^(guò)synthetic()和返回值 synth 調(diào)用,這里可以自定義異常顯示內(nèi)容,也可以修改resp.status與resp.http.Location重定向。
可操作對(duì)象:(部分或全部值)
讀:client,server,req,resp,storage
寫(xiě):req,resp
返回值:
deliver 只交付 sysnthetic(string) 自定義內(nèi)容,默認(rèn)返回 sysnth 異常指定狀態(tài)碼與錯(cuò)誤內(nèi)容。
restart 重啟請(qǐng)求。
  
vcl_init子程序:
加載vcl時(shí)最先調(diào)用,用于初始化VMODs,該子程序不參與請(qǐng)求處理,僅在vcl加載時(shí)調(diào)用一次。
可操作對(duì)象:(部分或全部值)
讀:server
寫(xiě):無(wú)
返回值:
ok 正常返回,進(jìn)入vcl_recv子程序,默認(rèn)返回值。
  
vcl_fini子程序:
卸載當(dāng)前vcl配置時(shí)調(diào)用,用于清理VMODs,該子程序不參與請(qǐng)求處理,僅在vcl正常丟棄后調(diào)用。
可操作對(duì)象:(部分或全部值)
讀:server
寫(xiě):無(wú)
返回值:
ok 正常返回,本次vcl將釋放,默認(rèn)返回值。
varnish子程序調(diào)用流程圖,通過(guò)大部分子程序的return返回值進(jìn)入下一步行動(dòng):

11)優(yōu)雅模式(Garce mode)

Varnish中的請(qǐng)求合并

當(dāng)幾個(gè)客戶(hù)端請(qǐng)求同一個(gè)頁(yè)面的時(shí)候,varnish只發(fā)送一個(gè)請(qǐng)求到后端服務(wù)器,然后讓其他幾個(gè)請(qǐng)求掛起并等待返回結(jié)果;獲得結(jié)果后,其它請(qǐng)求再?gòu)?fù)制后端的結(jié)果發(fā)送給客戶(hù)端;

但如果同時(shí)有數(shù)以千計(jì)的請(qǐng)求,那么這個(gè)等待隊(duì)列將變得龐大,這將導(dǎo)致2類(lèi)潛在問(wèn)題:

驚群?jiǎn)栴}(thundering herd problem),即突然釋放大量的線(xiàn)程去復(fù)制后端返回的結(jié)果,將導(dǎo)致負(fù)載急速上升;沒(méi)有用戶(hù)喜歡等待;

故為了解決這類(lèi)問(wèn)題,可以配置varnish在緩存對(duì)象因超時(shí)失效后再保留一段時(shí)間,以給那些等待的請(qǐng)求返回過(guò)去的文件內(nèi)容(stale content),配置案例如下:

1
2
3
4
5
6
7
8
9
10
11
12
sub vcl_recv {
if (! req.backend.healthy) {
set req.grace = 5m;
else {
set req.grace = 15s;
}
}
sub vcl_fetch {
set beresp.grace = 30m;
}
以上配置表示varnish將會(huì)將失效的緩存對(duì)象再多保留30分鐘,此值等于最大的req.grace值即可;
而根據(jù)后端主機(jī)的健康狀況,varnish可向前端請(qǐng)求分別提供5分鐘內(nèi)或15秒內(nèi)的過(guò)期內(nèi)容

二、安裝varnish

1、安裝依賴(lài)關(guān)系的軟件包(注:使用centos在線(xiàn)yum源)

1
[root@varnish ~]# yum -y install autoconf automake libedit-devel libtool ncurses-devel pcre-devel pkgconfig python-docutils python-sphinx

2、安裝varnish

Varnish的官方網(wǎng)址為http://varnish-cache.org,可以在這里下載最新版本的軟件。

下載地址:https://www.varnish-cache.org/content/varnish-cache-403

注意:Varnish網(wǎng)站有時(shí)會(huì)被墻。

Git 下載:

1
git clone https://github.com/varnish/Varnish-Cache /var/tmp/

解壓,進(jìn)入解壓目錄編譯安裝:

1
2
3
[root@varnish ~]# tar zxf varnish-4.0.3.tar.gz
[root@varnish ~]# cd varnish-4.0.3/
[root@varnish varnish-4.0.3]# export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

注:

./autogen.sh 

如果從Git庫(kù)下載的安裝包時(shí)才需要運(yùn)行,用于生成configure編譯文件。

配置:

1
[root@varnish varnish-4.0.3]# ./configure

注:不指定安裝路徑,默認(rèn)是安裝在/usr/local目錄下

編譯、安裝

1
[root@varnish varnish-4.0.3]# make && make install

復(fù)制 vcl 文件(在編譯安裝目錄下),如果安裝目錄里沒(méi)有 default.vcl 文件。

復(fù)制到安裝目錄的/usr/local/var/varnish/目錄下(當(dāng)然并無(wú)必需要求在哪個(gè)目錄,因?yàn)檎絾?dòng)時(shí)還得指定這個(gè)文件的目錄)

1
[root@varnish varnish-4.0.3]# cp etc/example.vcl  /usr/local/var/varnish/default.vcl

三、varnish實(shí)例解析:

varnish 配置基本上是編輯 VCL(Varnish Configuration Language) 文件,varnish 有一套自定義 VCL 語(yǔ)法,啟動(dòng)時(shí),會(huì)將配置文件編譯為C語(yǔ)言,再執(zhí)行。

varnish 4.0開(kāi)始,每個(gè)VCL文件必須在開(kāi)始行聲明它的版本“vcl 4.0;”

塊(子程序)由大括號(hào)分隔,語(yǔ)句用分號(hào)結(jié)束。所有的關(guān)鍵字及預(yù)設(shè)子程序名都是全小寫(xiě)。

注釋?zhuān)褐С?// 或 #  多行時(shí)還可以使用 /* .. */

1、后端服務(wù)器地址池配置及后端服務(wù)器健康檢查

varnish有"后端"或者"源"服務(wù)器的概念。backend server提供給varnish加速的內(nèi)容。實(shí)際上就是給varnish添加可供訪(fǎng)問(wèn)的web服務(wù)器,如果有多臺(tái)web服務(wù)器時(shí),可添加多個(gè)backend塊。

1)后端服務(wù)器定義:

命令:backend。這個(gè)定義為最基本的反向入口定義,用于varnish連接對(duì)應(yīng)的服務(wù)器,如果沒(méi)有定義或定義錯(cuò)誤則用戶(hù)無(wú)法訪(fǎng)問(wèn)正常頁(yè)面。

語(yǔ)法格式:

1
2
3
backend name{
    .attribute = "value";
}

說(shuō)明:backend 是定義后端關(guān)鍵字,name 是當(dāng)前后端節(jié)點(diǎn)的別名,多個(gè)后端節(jié)點(diǎn)時(shí),name 名不能重復(fù),否則覆蓋?;ɡㄌ?hào)里面定義當(dāng)前節(jié)點(diǎn)相關(guān)的屬性(鍵=值)。除默認(rèn)節(jié)點(diǎn)外其它節(jié)點(diǎn)定義后必需有調(diào)用,否則varnish無(wú)法啟動(dòng)。后端是否正??梢酝ㄟ^(guò)std.healthy(backend)判斷。

支持運(yùn)算符:

=   (賦值運(yùn)算)

==  (相等比較)

~    (匹配,可以使用正則表達(dá)式,或訪(fǎng)問(wèn)控制列表)

!~    (不匹配,可以使用正則表達(dá)式,或訪(fǎng)問(wèn)控制列表)

!  (非)

&&   (邏輯與)

||   (邏輯或)

屬性列表:

.host="xxx.xxx.xxx.xxx";      //要轉(zhuǎn)向主機(jī)(即后端主機(jī))的IP或域名,必填鍵/值對(duì)。
.port="8080";        //主機(jī)連接端口號(hào)或協(xié)議名(HTTP等),默認(rèn)80
.host_header='';    //請(qǐng)示主機(jī)頭追加內(nèi)容
.connect_timeout=1s;     //連接后端的超時(shí)時(shí)間
.first_byte_timeout=5s;    //等待從后端返回的第一個(gè)字節(jié)時(shí)間
.between_bytes_timeout=2s;     //每接收一個(gè)字節(jié)之間等待時(shí)間
.probe=probe_name;        //監(jiān)控后端主機(jī)的狀態(tài),指定外部監(jiān)控name或者內(nèi)部直接添加
.max_connections=200;    //設(shè)置最大并發(fā)連接數(shù),超過(guò)這個(gè)數(shù)后連接就會(huì)失敗

例:(下面兩個(gè)例子結(jié)果是一樣的,但第二個(gè)例子中更適用于集群,可以方便批量修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
backend web{
    .host="192.168.31.83";
    .port="80";
    .probe={          //直接追加監(jiān)控塊.probe是一個(gè)的參數(shù)
        .url="/";
        .timeout=2s;
    }
}
probe web_probe{   //監(jiān)控必需定義在前面,否則后端調(diào)用找不到監(jiān)控塊。
    .url="/";
    .timeout=2s;
}
  
backend web{
    .host="192.168.31.83";
    .port="80";
    .probe=web_probe;   //調(diào)用外部共用監(jiān)控塊
}

2)監(jiān)視器定義:

命令:probe 。監(jiān)控可以循環(huán)訪(fǎng)問(wèn)指定的地址,通過(guò)響應(yīng)時(shí)間判定服務(wù)器是否空閑或正常。這類(lèi)命令非常適用于集群中某些節(jié)點(diǎn)服務(wù)器崩潰或負(fù)載過(guò)重,而禁止訪(fǎng)問(wèn)這臺(tái)節(jié)點(diǎn)服務(wù)器。

語(yǔ)法格式:

1
2
3
probe name{
    .attribute = "value";
}

說(shuō)明:probe 是定義監(jiān)控關(guān)鍵字,name 是當(dāng)前監(jiān)控點(diǎn)的別名,多個(gè)監(jiān)控節(jié)點(diǎn)時(shí),name 名不能重復(fù),否則覆蓋。花括號(hào)里面定義當(dāng)前節(jié)點(diǎn)相關(guān)的屬性(鍵=值)。

沒(méi)有必填屬性,因?yàn)槟J(rèn)值就可以正常執(zhí)行操作。

屬性列表:

.url="/";    //指定監(jiān)控入口URL地址,默認(rèn)為"/"

.request="";   //指定監(jiān)控請(qǐng)求入口地址,比 .url 優(yōu)先級(jí)高。
.expected_response="200";   //請(qǐng)求響應(yīng)代碼,默認(rèn)是 200
.timeout=2s;   //請(qǐng)求超時(shí)時(shí)間。
.interval=5s;     //每次輪詢(xún)請(qǐng)求間隔時(shí)間,默認(rèn)為 5s 。
.initial=-1;     //初始啟動(dòng)時(shí)以.window輪詢(xún)次數(shù)中幾次良好后續(xù)才能使用這個(gè)后端服務(wù)器節(jié)點(diǎn),默認(rèn)為 -1 ,則輪詢(xún)完 .window 所有次數(shù)良好判定為正常。
.window=8;   //指定多少輪詢(xún)次數(shù),用于判定服務(wù)器正常,默認(rèn)是 8。
.threshold=3;   //必須多少次輪詢(xún)正常才算該后端節(jié)點(diǎn)服務(wù)器正常,默認(rèn)是 3。

例:創(chuàng)建健康監(jiān)測(cè),定義健康檢查名稱(chēng)為backend_healthcheck

1
2
3
4
5
6
7
probe backend_healthcheck {
        .url = "/";
        .timeout = 1s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }

在上面的例子中varnish將每5s檢測(cè)后端,超時(shí)設(shè)為1s。每個(gè)檢測(cè)將會(huì)發(fā)送get /的請(qǐng)求。如果5個(gè)檢測(cè)中大于3個(gè)是成功,varnish就認(rèn)為后端是健康的,反之,后端就有問(wèn)題了。

 

3)集群負(fù)載均衡directors:

varnish可以定義多個(gè)后端,也可以將幾個(gè)后端放在一個(gè)后端集群里面已達(dá)到負(fù)載均衡的目的。

你也可以將幾個(gè)后端組成一組后端。這個(gè)組被叫做Directors。可以提高性能和彈性。

directors是varnish負(fù)載均衡模塊,使用前必需引入directors模塊,directors模塊主要包含:round_robin,random,hash,fallback負(fù)載均衡模式。

round_robin : 循環(huán)依次逐個(gè)選擇后端服務(wù)器。

random : 隨機(jī)選擇后端服務(wù)器,可設(shè)置每個(gè)后端權(quán)重增加隨機(jī)率。

hash :  通過(guò)散列隨機(jī)選擇對(duì)應(yīng)的后端服務(wù)器且保持選擇對(duì)應(yīng)關(guān)系,下次則直接找對(duì)應(yīng)的后端服務(wù)器。

Fallback:后備

注意:random,hash 有權(quán)重值設(shè)置,用于提高隨機(jī)率。每個(gè)后端最好都配置監(jiān)控器(后端服務(wù)器正常監(jiān)測(cè))以便directors自動(dòng)屏蔽不正常后端而不進(jìn)入均衡列隊(duì)中。

這些操作需要你載入VMOD(varnish module),然后在vcl_init中調(diào)用這個(gè)VMOD。

1
2
3
4
5
6
7
8
9
10
11
import directors;                # load the directors
backend web1 {
.host = "192.168.0.10";
.port = "80";
.probe = backend_healthcheck;
}
backend web2 {
.host = "192.168.0.11";
.port = "80";
.probe = backend_healthcheck;
}

//初始化處理

sub vcl_init {            //調(diào)用vcl_init初始化子程序創(chuàng)建后端主機(jī)組,即directors

    new  web_cluster = directors.round_robin(); //使用new關(guān)鍵字創(chuàng)建drector對(duì)象,使用round_robin算法

    web_cluster.add_backend(web1);   //添加后端服務(wù)器節(jié)點(diǎn)

web_cluster.add_backend(web2);

}

//開(kāi)始處理請(qǐng)求

sub vcl_recv {                     //調(diào)用vcl_recv子程序,用于接收和處理請(qǐng)求

    set  req.backend_hint = web_cluster.backend();     //選取后端

}

說(shuō)明:

set命令是設(shè)置變量

unset命令是刪除變量

web_cluster.add_backend( backend , real );  添加后端服務(wù)器節(jié)點(diǎn),backend 為后端配置別名,real 為權(quán)重值,隨機(jī)率計(jì)算公式:100 * (當(dāng)前權(quán)重 / 總權(quán)重)。

req.backend_hint是varnish的預(yù)定義變量,作用是指定請(qǐng)求后端節(jié)點(diǎn)

vcl對(duì)象需要使用new關(guān)鍵字創(chuàng)建,所有可創(chuàng)建對(duì)象都是內(nèi)定的,使用前必需import,所有new操作只能在vcl_init子程序中。

擴(kuò)展:varnish將不同的url發(fā)送到不同的后端server

i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
mport directors;                # load the directors
backend web1 {
.host = "192.168.0.10";
.port = "80";
.probe = backend_healthcheck;
}
backend web2 {
.host = "192.168.0.11";
.port = "80";
.probe = backend_healthcheck;
}
backend img1 {
        .host = "img1.lnmmp.com";
        .port = "80";
        .probe = backend_healthcheck;
}
backend img2 {
        .host = "img2.lnmmp.com";
        .port = "80";
        .probe = backend_healthcheck;
}
//初始化處理
sub vcl_init {            //調(diào)用vcl_init初始化子程序創(chuàng)建后端主機(jī)組,即directors
    new  web_cluster = directors.round_robin(); //使用new關(guān)鍵字創(chuàng)建drector對(duì)象,使用round_robin算法
    web_cluster.add_backend(web1);   //添加后端服務(wù)器節(jié)點(diǎn)
web_cluster.add_backend(web2);
new img_cluster = directors.random();
img_cluster.add_backend(img1,2);   //添加后端服務(wù)器節(jié)點(diǎn),并且設(shè)置權(quán)重值
img_cluster.add_backend(img2,5);
}
//根據(jù)不同的訪(fǎng)問(wèn)域名,分發(fā)至不同的后端主機(jī)組
sub vcl_recv {
if (req.http.host  ~  "(?i)^(www.)?benet.com$") {
                set  req.http.host = "www.benet.com";
                set  req.backend_hint = web_cluster.backend();  //選取后端
        } elsif (req.http.host  ~  "(?i)^images.benet.com$") {
            set  req.backend_hint = img_cluster.backend();
        }
}

說(shuō)明:中的i就是忽略大小寫(xiě)的意思。(?i)表示開(kāi)啟忽略大小寫(xiě),而(?-i)表示關(guān)閉忽略大小寫(xiě)

 

4)訪(fǎng)問(wèn)控制列表(ACL):

創(chuàng)建一個(gè)地址列表,用于后面的判斷,可以是域名或IP集合。這個(gè)可以用于指定某些地址請(qǐng)求入口,防止惡意請(qǐng)求等。

語(yǔ)法格式:

1
2
3
4
5
6
acl  purgers  {
    "127.0.0.1";
"localhost";
“192.168.134.0/24
    !"192.168.134.1";
}

說(shuō)明:acl 是訪(fǎng)問(wèn)列表關(guān)鍵字(必需小寫(xiě)),name 是該列表的別名用于調(diào)用,花括號(hào)內(nèi)部是地址集。

注意:如果列表中包含了無(wú)法解析的主機(jī)地址,它會(huì)匹配任何地址。

如果不想讓它匹配可以在前添加一個(gè) ! 符號(hào),如上面 !"192.168.134.1"; 

使用ACL只需要用 匹配運(yùn)算符 ~ 或 !~  如:

1
2
3
4
5
6
7
8
9
sub  vcl_recv {
    if  (req.method == "PURGE") {    //PURGE請(qǐng)求的處理
         if  (client.ip  ~  purgers) {
              return(purge);
         else {
            return(synth(403, "Access denied."));
        }
    }
}

5)緩存規(guī)則配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
sub vcl_recv {
  // PURGE請(qǐng)求的處理
  if (req.method == "PURGE") {
    if (!client.ip ~ purgers) {
      return (synth(405, "Not Allowed."));
    }
    return (purge);
  }
  
  set req.backend_hint = web.backend();
  
  //將php、asp等動(dòng)態(tài)內(nèi)容訪(fǎng)問(wèn)請(qǐng)求直接發(fā)給后端服務(wù)器,不緩存。
  if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {
    return (pass);
  }
  //將非GET和HEAD訪(fǎng)問(wèn)請(qǐng)求直接發(fā)給后端服務(wù)器,不緩存。例如POST請(qǐng)求。
  if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
  }
  //如果varnish看到header中有'Authorization'頭,它將pass請(qǐng)求。
  if (req.http.Authorization) {
        return (pass);
}
  
  //帶cookie首部的GET請(qǐng)求也緩存
  if (req.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
    unset req.http.cookie;
    return (hash);
  }

說(shuō)明:默認(rèn)情況,varnish不緩存從后端響應(yīng)的http頭中帶有Set-Cookie的對(duì)象。如果客戶(hù)端發(fā)送的請(qǐng)求帶有Cookie header,varnish將忽略緩存,直接將請(qǐng)求傳遞到后端。

 

//為發(fā)往后端主機(jī)的請(qǐng)求添加X(jué)-Forward-For首部,首次訪(fǎng)問(wèn)增加 X-Forwarded-For 頭信息,方便后端程序獲取客戶(hù)端ip,而不是varnish地址

1
2
3
4
5
6
7
if (req.restarts == 0) {
        if (req.http.x-forwarded-for) {//如果設(shè)置過(guò)此header則要再次附加上用逗號(hào)隔開(kāi)
            set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
        else {//如果只有一層代理的話(huà),就無(wú)需設(shè)置了
            set req.http.X-Forwarded-For = client.ip;
        }
}

說(shuō)明:X-Forwarded-For 是用來(lái)識(shí)別通過(guò)HTTP代理或負(fù)載均衡方式連接到Web服務(wù)器的客戶(hù)端最原始的IP地址的HTTP請(qǐng)求頭字段

子程序:

 

子程序是一種類(lèi)似C的函數(shù),但是程序沒(méi)有調(diào)用參數(shù),子程序以 sub 關(guān)鍵字定義。在VCL里子程序是用于管理程序。

注意:所有VCL內(nèi)置的程序都是以 vcl_ 開(kāi)頭,并已經(jīng)預(yù)置好,在VCL文件中只要聲明對(duì)應(yīng)的內(nèi)置子程序,都會(huì)在對(duì)應(yīng)的流程中調(diào)用。

三、varnish完整配置實(shí)例

1、拓?fù)洵h(huán)境

1
2
3
Varnish:192.168.31.250
Web01:192.168.31.83
Web02:192.168.31.141

配置web01、web02做為后端服務(wù)器(過(guò)程略)

確保varnish服務(wù)器能正常訪(fǎng)問(wèn)web01、web02

Varnish緩存代理服務(wù)器配置:

2、vcl文件配置內(nèi)容:

1
[root@varnish ~]# cat  /usr/local/var/varnish/default.vcl

#使用varnish版本4的格式.

1
vcl 4.0;

#加載后端負(fù)載均衡模塊

1
import directors;

#加載std模塊

1
import std;

#創(chuàng)建名為backend_healthcheck的健康檢查策略

1
2
3
4
5
6
7
probe backend_healthcheck {
    .url="/";
    .interval = 5s;
    .timeout = 1s;
    .window = 5;
    .threshold = 3;
}

#定義后端服務(wù)器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
backend web_app_01 {
    .host = "192.168.31.83";
    .port = "80";
    .first_byte_timeout = 9s;
    .connect_timeout = 3s;
    .between_bytes_timeout = 1s;
    .probe = backend_healthcheck;
}
backend web_app_02 {
    .host = "192.168.31.141";
    .port = "80";
    .first_byte_timeout = 9s;
    .connect_timeout = 3s;
    .between_bytes_timeout = 1s;
    .probe = backend_healthcheck;
}

#定義允許清理緩存的IP

1
2
3
4
5
acl purgers {
    "127.0.0.1";
    "localhost";
    "192.168.31.0/24";
}

#vcl_init初始化子程序創(chuàng)建后端主機(jī)組

1
2
3
4
5
sub vcl_init {
    new web = directors.round_robin();
    web.add_backend(web_app_01);
    web.add_backend(web_app_02);
}

#請(qǐng)求入口,用于接收和處理請(qǐng)求。這里一般用作路由處理,判斷是否讀取緩存和指定該請(qǐng)求使用哪個(gè)后端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
sub vcl_recv {
    #將請(qǐng)求指定使用web后端集群 .在集群名后加上 .backend()
set req.backend_hint = web.backend();
# 匹配清理緩存的請(qǐng)求
    if (req.method == "PURGE") {
        if (!client.ip ~ purgers) {
            return (synth(405, "Not Allowed."));
        }
        # 是的話(huà)就執(zhí)行清理
        return (purge);
    }
    # 如果不是正常請(qǐng)求 就直接穿透沒(méi)商量
    if (req.method != "GET" &&
      req.method != "HEAD" &&
      req.method != "PUT" &&
      req.method != "POST" &&
      req.method != "TRACE" &&
      req.method != "OPTIONS" &&
      req.method != "PATCH" &&
      req.method != "DELETE") {
      return (pipe);
    }
    # 如果不是GET和HEAD就跳到pass 
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }
    #如果匹配動(dòng)態(tài)內(nèi)容訪(fǎng)問(wèn)請(qǐng)求就跳到pass
    if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {
        return (pass);
    }
    #具有身份驗(yàn)證的請(qǐng)求跳到pass
    if (req.http.Authorization) {
        return (pass);
    }
  
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$") {
            unset req.http.Accept-Encoding;
        } elseif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elseif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        else {
            unset req.http.Accept-Encoding;
        }
    }
  
    if (req.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
        unset req.http.cookie;
        return (hash);
}

# 把真實(shí)客戶(hù)端IP傳遞給后端服務(wù)器 后端服務(wù)器日志使用X-Forwarded-For來(lái)接收

   

1
2
3
4
5
6
7
8
9
 if (req.restarts == 0) {
        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;
        }
    }
    return (hash);
}

# hash事件(緩存事件)

1
2
3
4
5
6
7
8
9
sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    else {
        hash_data(server.ip);
    }
    return (lookup);
}

# 緩存命中事件

1
2
3
4
5
6
sub vcl_hit {
    if (req.method == "PURGE") {
        return (synth(200, "Purged."));
    }
    return (deliver);
}

# 緩存不命中事件

1
2
3
4
5
6
sub vcl_miss {
    if (req.method == "PURGE") {
        return (synth(404, "Purged."));
    }
    return (fetch);
}

# 返回給用戶(hù)的前一個(gè)事件 通常用于添加或刪除header頭

1
2
3
4
5
6
7
sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    else {
        set resp.http.X-Cache = "MISS";
}

#取消顯示php框架版本的header頭

1
unset resp.http.X-Powered-By;

#取消顯示web軟件版本、Via(來(lái)自varnish)等header頭 為了安全

   

1
2
3
4
5
 unset resp.http.Server;
    unset resp.http.X-Drupal-Cache;
    unset resp.http.Via;
    unset resp.http.Link;
unset resp.http.X-Varnish;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#顯示請(qǐng)求經(jīng)歷restarts事件的次數(shù)
set resp.http.xx_restarts_count = req.restarts;
#顯示該資源緩存的時(shí)間單位秒
set resp.http.xx_Age = resp.http.Age;
#顯示該資源命中的次數(shù)
set resp.http.hit_count = obj.hits;
#取消顯示Age 為了不和CDN沖突
unset resp.http.Age;
#返回給用戶(hù)
    return (deliver);
}
# pass事件
sub vcl_pass {
    return (fetch);
}
#處理對(duì)后端返回結(jié)果的事件(設(shè)置緩存、移除cookie信息、設(shè)置header頭等) 在fetch事件后自動(dòng)調(diào)用
sub vcl_backend_response {
    #開(kāi)啟grace模式 表示當(dāng)后端全掛掉后 即使緩存資源已過(guò)期(超過(guò)緩存時(shí)間) 也會(huì)把該資源返回給用戶(hù) 資源最大有效時(shí)間為5分鐘
set beresp.grace = 5m;
#后端返回如下錯(cuò)誤狀態(tài)碼 則不緩存
    if (beresp.status == 499 || beresp.status == 404 || beresp.status == 502) {
    set beresp.uncacheable = true;
}
#如請(qǐng)求php或jsp 則不緩存
    if (bereq.url ~ "\.(php|jsp)(\?|$)") {
      set beresp.uncacheable = true;
    else //自定義緩存文件的緩存時(shí)長(zhǎng),即TTL值
       if (bereq.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico)($|\?)") {
         set beresp.ttl = 15m;
         unset beresp.http.Set-Cookie;
       } elseif (bereq.url ~ "\.(gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
           set beresp.ttl = 30m;
           unset beresp.http.Set-Cookie;
         else {
            set beresp.ttl = 10m;
            unset beresp.http.Set-Cookie;
         }
      }
    #返回給用戶(hù)
    return (deliver);
}
sub vcl_purge {
        return (synth(200,"success"));
}
  
sub vcl_backend_error {
    if (beresp.status == 500 ||
        beresp.status == 501 ||
        beresp.status == 502 ||
        beresp.status == 503 ||
        beresp.status == 504) {
        return (retry);
    }
}
  
sub vcl_fini {
    return (ok);
}

3、啟動(dòng)varnish

當(dāng)啟動(dòng)varnish時(shí)有兩個(gè)重要的參數(shù)你必須設(shè)置: 一個(gè)是處理http請(qǐng)求的tcp監(jiān)聽(tīng)端口,另一個(gè)是處理真實(shí)請(qǐng)求的后端server

注:如果你使用操作系統(tǒng)自帶的包管理工具安裝的varnish,你將在下面的文件找到啟動(dòng)參數(shù):

Red Hat, Centos: /etc/sysconfig/varnish


1):'-a' 參數(shù)定義了varnish監(jiān)聽(tīng)在哪個(gè)地址,并用該地址處理http請(qǐng)求,你可能想設(shè)置這個(gè)參數(shù)在眾所周知的http 80端口.

例子:

-a  :80

-a  localhost:80

-a  192.168.1.100:8080

-a  '[fe80::1]:80'

-a  '0.0.0.0:8080,[::]:8081'

如果你的webserver和varnish運(yùn)行在同一臺(tái)機(jī)器,你必須換一個(gè)監(jiān)聽(tīng)地址.

2):'-f'  VCL-file  or  '-b'  backend

-f添加vcl文件,-b定義后端server

varnish需要知道從哪里找到這個(gè)需要緩存的http server.你可以用-b參數(shù)指定,或者幫把它放在vcl文件中,然后使用-f參數(shù)指定.

在啟動(dòng)的時(shí)候使用-b是一個(gè)快捷的方式.

-b 192.168.1.2:80

注意:如果你指定的是name,這個(gè)name必須能解析成一個(gè)IPv4或者IPv6的地址

如果你使用-f參數(shù),你啟動(dòng)的時(shí)候可以在-f指定vcl文件。

默認(rèn)的varnish使用100M的內(nèi)存來(lái)緩存對(duì)象,如果你想緩存更多,可以使用-s參數(shù). 

注:Varnish擁有大量的有用的命令行參數(shù),建議查看其幫助

1
[root@varnish ~]# /usr/local/sbin/varnishd -h

啟動(dòng)varnish

1
2
3
4
[root@varnish ~]# /usr/local/sbin/varnishd -f /usr/local/var/varnish/default.vcl -s malloc,200M -a
0.0.0.0:80
[root@varnish ~]# netstat -anpt | grep 80
tcp     0   0 0.0.0.0:80      0.0.0.0:*      LISTEN      6173/varnishd

2)現(xiàn)在,varnish已經(jīng)啟動(dòng)和運(yùn)行,你可以通過(guò)varnish訪(fǎng)問(wèn)您的Web應(yīng)用程序。

打開(kāi)火狐瀏覽器

第一次訪(fǎng)問(wèn)

第二次訪(fǎng)問(wèn)

3)varnish4配置手動(dòng)清除緩存

varnish4通過(guò)vcl配置清楚緩存

通過(guò)vcl配置可以讓客戶(hù)端手動(dòng)請(qǐng)求清楚緩存,以保證局部數(shù)據(jù)及時(shí)更新,而不用重啟varnish服務(wù)器。

配置方法:

#允許清除緩存IP集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
acl purgers {
    "127.0.0.1";
    "localhost";
    "192.168.31.0/24";
}
sub vcl_recv {
    ……
    if (req.method == "PURGE") {
        if (!client.ip ~ purgers) {
            return (synth(405, "Not Allowed."));
        }
        return (purge);   //清除緩存
}
……
}
sub vcl_purge {
        return (synth(200,"success"));
}


打開(kāi)火狐瀏覽器,隨便進(jìn)入一個(gè)緩存頁(yè)面,如下圖所示。

點(diǎn)擊編輯和重發(fā), 修改請(qǐng)求類(lèi)型為 PURGE 再點(diǎn)擊 發(fā)送

查看返回狀態(tài),如果成功則成功清除緩存,可以按 F5 刷新頁(yè)面,查看新內(nèi)容。

 


本文出自 “一盞燭光” 博客,謝絕轉(zhuǎn)載!

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)