1、varnish簡介php
varnish是一款高性能且開源的反向代理服務器和HTTP加速器,其採用全新的軟件設置體系機構,和現的的硬件體系緊密配合,與傳遞的squid相比,varnish相比,varnish具備性能更高、速度更快、管理更加方便等諸多優勢。css
2、 varnish軟件體系架構html
varnish主要運行兩個進程:Management進程和Child進程。node
Management進程主要實現應用新的配置、編譯VCL、監控varnish、初始化varnish以及提供一個命令行接口等。Management進程會每隔幾秒鐘探測一下Child進程以判斷其是否正常運行,若是在指定的時長內未獲得Child進程的迴應,Management將會重啓此Child進程。web
Child進程包含多種類型的線程,常見的如:編程
Acceptor線程:接收新的鏈接請求並響應;後端
Worker線程:child進程會爲每一個會話啓動一個worker線程,所以,在高併發的場景中可能會出現數百個worker線程甚至更多;瀏覽器
Expiry線程:從緩存中清理過時內容;緩存
3、 VCLbash
VCL是VarnishConfiguration Language,即Varnish配置語言,它提供了一個控制Varnish工做的接口,用於編寫緩存策略配置工具,它是一個基於「域」的簡單編程語言,「域」在一狀況下稱爲varnish的狀態引擎。
下圖來自varnish官方,能夠狀況的看到每個狀態的轉換。
3.1 VCL狀態引擎
vcl_recv |
請求被接入,但在其被分析、處理完成以前,決定選擇一下步的策略動做 |
vcl_pipe |
不經由varnish直接將請求發日後端主機的時候調用,請求和內容不作任何改變,如同爲客戶端和backend創建一個管道 |
vcl_pass |
將請求直接發給backend,而不是用緩存中的數據響應客戶端 |
vcl_hash |
對URL進行hash,能夠自定義hash鍵 |
vcl_hit |
在緩存中找到對象時執行的動做 |
vcl_miss |
未在緩存中找到對象時執行的動做 |
vcl_fetch |
從後端主機獲取內容,並判斷是否緩衝此內容,而後響應給客戶端 |
vcl_deliver |
響應客戶端時執行的動做 |
vcl_error | 在varnishi上合成錯誤響應頁時,調用此函數 |
4、經常使用變量
4.1 在任何狀態引擎中都可使用
.now:獲取當前系統當前時間
.host:後端主機的IP地址或主機名
.port:後端主機的端口號或服務名
4.2 用於處理請求階段:(vcl_recv,vcl_hash,vcl_pass,vcl_pipe)
client.ip:客戶端的IP地址
server.hostname:varnish緩存服務器的主機名
server.ip:varnish緩存服務器的IP地址
server.port:varnish緩存服務器的端口
req.request:請求方法(例:「GET」,「HEAD」)
req.url: 請求的URL
req.proto: HTTP協議版本
req.backend: 用於服務這次請求的後端主機;
req.backend.healthy: 後端主機健康狀態;
req.http.HEADER: 引用請求報文中指定的首部; (如:req.http.host)
req.can_gzip:客戶端是否可以接受gzip壓縮格式的響應內容;
req.restarts: 此請求被重啓的次數;(如重定向以後就要進行restart)
4.3 varnish向backend主機發起請求前可用的變量
bereq.request: 請求方法
bereq.url
bereq.proto
bereq.http.HEADER
bereq.connect_timeout: 等待與backend創建鏈接的超時時長
4.4 backend主機的響應報文到達本主機(varnish)後,將其放置於cache中以前可用的變量
beresp.do_stream: 流式響應;
beresp.do_gzip:是否壓縮以後再存入緩存;默認爲false
beresp.do_gunzip:當收到後端服務器的壓縮報文時,是否解壓以後在存入緩存,默認爲false
beresp.http.HEADER:
beresp.proto:
beresp.status:響應狀態碼
beresp.response:響應時的緣由短語
beresp.ttl:響應對象剩餘的生存時長,單位爲second;
beresp.backend.name: 此響應報文來源backend名稱;
beresp.backend.ip:此響應報文來源backend IP地址
beresp.backend.port:此響應報文來源backend 端口
beresp.storage
4.5 緩存對象存入cache以後可用的變量
obj.proto:響應時的協議
obj.status:響應時的狀態碼
obj.response:響應時的緣由短語
obj.ttl
obj.hits:緩存對象被用於當着響應時的次數
obj.http.HEADER
4.6 在決定對請求鍵作hash計算時可用的變量
req.hash:指明把什麼當着hash鍵來查詢緩存的鍵
4.7 在爲客戶端準備響應報文時可用的變量
resp.proto
resp.status
resp.response
resp.http.HEADER
4.8 快速記憶表
5、安裝varnish
5.1 安裝varnish
varnish-3.0.6-1.el6.x86_64.rpm varnish-docs-3.0.6-1.el6.x86_64.rpm varnish-libs-3.0.6-1.el6.x86_64.rpm rpm -ivh varnish-3.0.6-1.el6.x86_64.rpmvarnish-libs-3.0.6-1.el6.x86_64.rpm varnish-docs-3.0.6-1.el6.x86_64.rpm #可能會依賴於gcc
5.2 查看相應生成的文件
/etc/rc.d/init.d/varnishlog #把內存中的日誌讀入到日誌文件 /etc/rc.d/init.d/varnishncsa /etc/rc.d/init.d/varnish #服務腳本程序 /etc/sysconfig/varnish #varnish配置文件 /etc/varnish/default.vcl #varnish策略文件
5.3 /etc/sysconfig/varnish配置文件解釋
[root@node-02 ~]# egrep -v "#|^$"/etc/sysconfig/varnish NFILES=131072 #所能打開的文件數,會自動調整 MEMLOCK=82000 #內存鎖空間 NPROCS="unlimited" #單個用戶或進程所能運行的線程數 RELOAD_VCL=1 #是否自動裝載緩存策略文件,當使用腳本啓動時varish會自動的去裝載配置文件 VARNISH_VCL_CONF=/etc/varnish/default.vcl #默認讀取的緩存策略文件路徑 VARNISH_LISTEN_PORT=6081 #varnish監聽的端口,如http的80端口 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 #用於CLI的管理的地址 VARNISH_ADMIN_LISTEN_PORT=6082 #用於CLI的管理的端口 VARNISH_SECRET_FILE=/etc/varnish/secret #密碼文件路徑 VARNISH_MIN_THREADS=50 #啓動的最小線程數 VARNISH_MAX_THREADS=1000 #最多的線程數,即爲最大的併發數,不能超出5000,過了就不維定 VARNISH_THREAD_TIMEOUT=120 #空閒線程空閒超時時間 VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin #varnish緩存文件,即爲緩存類型爲文件 VARNISH_STORAGE_SIZE=1G #緩存大小 VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${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}"
5.4 解析默認的defaults.vcl文件中的vcl_recv中的內容
sub vcl_recv { if (req.restarts == 0) { #重啓次數爲0,即爲第一次訪問 if(req.http.x-forwarded-for) { #「req.http.x-forwarded-for」的值爲空或爲NULL,即爲真 set req.http.X-Forwarded-For = req.http.X-Forwarded-For+ ", " + client.ip; #當「X-Forwarded-For」首部信息中有值, #就在其值後加上一個「,」和客戶端的IP地址;用於在後端服務器記錄真實的客戶端的IP地址, }else { set req.http.X-Forwarded-For = client.ip; } } 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); #不是標準的HTTP請求方法,直接送日後端服務器 } if (req.request != "GET" && req.request !="HEAD") { /* We only deal with GET and HEAD by default */ return (pass); #不是「GET」和「HEAD」就不查詢緩存,直接送日後端服務器 } if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); #當有認證或cookie時不查詢緩存,直接送日後端服務器 } return (lookup); #任何一個函數在遇到return時就會返回,如下都不在執行;return (lookup)將將由vcl_hash }
5.5 解析默認的defaults.vcl中的vcl_hash
subvcl_hash { hash_data(req.url); #獲取請求的URL if (req.http.host) { #若是請求的host不空 hash_data(req.http.host); } else { hash_data(server.ip); } return (hash); #從新回到hash從hash計算 }
5.6 解析默認的defaults.vcl中的vcl_fetch
sub vcl_fetch { if (beresp.ttl <= 0s || #beresp後端主機的響應報文收到放到緩存以前 beresp.http.Set-Cookie || beresp.http.Set-Cookie || beresp.http.Vary == "*") { /* * Mark as"Hit-For-Pass" for the next 2 minutes */ set beresp.ttl = 120 s; return (hit_for_pass); } return (deliver); }
6、varnish實驗
6.1 實驗拓撲
6.2 實驗規劃
(1)實現動靜分離,Web-01用於解析php,Web-01和Web-02都解析靜態的頁面
(2)緩存靜態內容,只緩存GET和HEAD方法,不緩存帶有cookie的內容,URL中包含靜態資源的,不緩存動態資源的請求
(3)增長一個HTTP首部信息,顯示是否命中
(4)設置清理緩存PURGE
(5)實現後端主機的健康檢查
6.3 VCL文件defaluts.vcl
[root@node-02 varnish]# egrep -v"#|^$" default.vcl probe healthcheck { #定義健康檢測方法 .url = "/index.html"; .interval = 60s; .timeout = 0.3 s; .window = 8; .threshold = 3; .initial = 3; .expected_response = 200; } backend PHP { #定義後端服務器 .host = "192.168.9.181"; .port = "80"; .probe = healthcheck; } backend web { .host = "192.168.9.182"; .port = "80"; .probe = healthcheck; } director svrs random { #定義服務器組 {.backend = PHP; .weight = 1;} {.backend = web; .weight = 1;} } acl purgers { #定義purger的訪問控制列表 "127.0.0.1"; "192.168.9.0"/24; } subvcl_recv { if (req.restarts == 0) { if (req.http.x-forwarded-for) { setreq.http.X-Forwarded-For = req.http.X-Forwarded-For + ", "+ client.ip; } else { setreq.http.X-Forwarded-For = client.ip; } } #若是是PURGE方法,且不是ACL中的,直接返回錯誤,若是是ACL中的將繼續 if (req.request == "PURGE") { if (!client.ip ~ purgers) { error 405 "Method not allowd"; } return(lookup); } #非指定的HTTP請求訪求,將直接訪問後端服務器 if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "PURGE" && req.request !="DELETE") { return (pipe); } #若是不是GET、HEAD方法,就不查緩存 if (req.request != "GET" && req.request !="HEAD") { return (pass); } #若是是認證和cookie則不查緩存 if (req.http.Authorization || req.http.Cookie) { return (pass); } #若是訪問php頁面,就不查緩存,將會直接指向後端服務器處理請求 if (req.url ~ "\.php($|\?)") { setreq.backend = PHP; return(pass); } #指定後端響應的服務器組 set req.backend = svrs; return (lookup); } subvcl_pass { #若是PURGE被送至這次將會被pass if (req.request == "PURGE") { error502 "PURGE on a passed object"; } return (pass); } subvcl_hit { #purge函數就是移除這個obj對應的全部變量緩存 if (req.request == "PURGE") { purge; error200 "Purged"; } return (deliver); } subvcl_miss { #直接經過vcl_error返回客戶端 if (req.request == "PURGE") { purge; error404 "Not in cache"; } return (fetch); } sub vcl_fetch{ #若是響應的ttl小於0秒或者使用了cookie或Very,則不緩存直接返回給客戶端 if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") { set beresp.ttl = 120 s; return (hit_for_pass); } #對於GET方法與請求的不一樣靜態資源使用不一樣的緩存時長 if (req.request == "GET") { if(req.url ~ "\.(css|js|html|htm)") { setberesp.ttl = 10m; } elseif(req.url ~ "\.(gif|jpg|jpeg|png)") { setberesp.ttl = 30m; } elseif(req.url ~ "\.ico") { setberesp.ttl = 30d; } } return (deliver); } subvcl_deliver { #返回客戶端以前,添加一個HTTP首部信息 if (obj.hits>0) { setresp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } return (deliver); }
6.4 修改/etc/sysconfig/varnish文件
VARNISH_LISTEN_PORT=80 VARNISH_MEM_SIZE=32M VARNISH_STORAGE="malloc,${VARNISH_MEM_SIZE}"
6.5 啓動varnish
[root@node-02 ~]# service varnish start Starting Varnish Cache: [ OK ] [root@node-02 ~]# ss -tanp |grep"80" LISTEN 0 128 :::80 :::* users:(("varnishd",4134,8)) LISTEN 0 128 *:80 *:* users:(("varnishd",4134,7))
6.6 Web服務頁面顯示信息
Web服務器的配置域名是www.c.org,須要配置DNS服務器或更改hosts文件。
[root@node-01 html]# cat index.htmlindex.php <h1>Html Static Web-01</h1> <h1>Real Server node-01</h1> [root@node-02 html]# cat index.htmlindex.php <h1>Html Static Web-02</h1> <h1>Real Server node-02</h1>
6.7 訪問靜態頁面
第一次訪問時未命令中緩存,由於緩存中根據就沒有緩存到有內容。
當再次刷新瀏覽器是查看響應報文首部信息已是「HIT」
6.8 訪問動態內容
當訪問後綴是php頁面時,varnish不會緩存內容,因此不斷的刷新都會是「MISS」
6.9 purge清理緩存
當更新了後端的Web服務器的內容時,就須要清理一些緩存信息,讓用戶訪問的頁面內容是最新的,使用curl命令經過-X選項傳遞一個HTTP首部信息。須要在hosts文件中添加一條www.c.org的解析,由於varnish緩存是根據用戶請求的URL做爲鍵的,當你使用IP地址又是一個新的鍵了,因此是沒法清理緩存中的信息。
curl -I -X PURGE http://varniship/path/to/someurl
使用crul訪問www.c.org/index.html頁面,查看請求的響應首部信息
[root@node-02 ~]# curl -I www.c.org/index.html HTTP/1.1 200 OK Server: Apache/2.2.15 (CentOS) Last-Modified: Sat, 13 Jun 2015 05:41:09GMT ETag: "120632-1c-5185fabf370f0" Content-Type: text/html; charset=UTF-8 Content-Length: 28 Accept-Ranges: bytes Date: Sun, 14 Jun 2015 12:09:40 GMT X-Varnish: 1227901809 Age: 0 Via: 1.1 varnish Connection: keep-alive X-Cache: MISS #第一次請求未命中 [root@node-02 ~]# curl -I www.c.org/index.html HTTP/1.1 200 OK Server: Apache/2.2.15 (CentOS) Last-Modified: Sat, 13 Jun 2015 05:41:09GMT ETag: "120632-1c-5185fabf370f0" Content-Type: text/html; charset=UTF-8 Content-Length: 28 Accept-Ranges: bytes Date: Sun, 14 Jun 2015 12:09:43 GMT X-Varnish: 1227901810 1227901809 Age: 2 Via: 1.1 varnish Connection: keep-alive X-Cache: HIT #再次請求命中
清理緩存index.html
[root@node-02 ~]# curl -I -X PURGE www.c.org/index.html HTTP/1.1 200 Purged #第一次清理成功 Server: Varnish Content-Type: text/html; charset=utf-8 Retry-After: 5 Content-Length: 380 Accept-Ranges: bytes Date: Sun, 14 Jun 2015 12:14:04 GMT X-Varnish: 1227901815 Age: 0 Via: 1.1 varnish Connection: close X-Cache: MISS [root@node-02 ~]# curl -I -X PURGE www.c.org/index.html HTTP/1.1 404 Not in cache #第二次清理告知沒有緩存 Server: Varnish Content-Type: text/html; charset=utf-8 Retry-After: 5 Content-Length: 398 Accept-Ranges: bytes Date: Sun, 14 Jun 2015 12:14:07 GMT X-Varnish: 1227901816 Age: 0 Via: 1.1 varnish Connection: close X-Cache: MISS
小結:
varnish是一個很是優秀強大的緩存服務器,它已經在大型的生產環境中獲得了普遍的運用,已經經得起考驗,不一樣的業務要根據不一樣的業務進行分析,一個好的緩存服務器能命中80%的內容,這樣對後端服務器的訪問的壓力是有多麼的重要是你能夠想想的,如今的互聯網產業是嚴重的依賴於緩存服務器。