防偽碼:你必須非常努力,才能看起來(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)載!
更多建議: