0.Varnish介紹(程序架構,原理)
Varnish是一款高性能的開源HTTP加速器,具有反向代理,緩存的功能。

緩存類型:代理式緩存(遞歸方式);旁掛式緩存(迭代)
緩存機制:過期機制(Expires)、條件式緩存(通過最近文件修改時間戳或Etag的擴展標簽來辨別)。
過期時間:Expires
HTTP/1.0
Expires:過期
HTTP/1.1
Cache-Control: maxage= (私有緩存,單位秒)
Cache-Control: s-maxage= (共有緩存)
緩存層級:
私有緩存:用戶代理附帶的本地緩存機制;
公共緩存:反向代理服務器的緩存功能;
條件式請求:
Last-Modified/If-Modified-Since:基於文件的修改時間戳來
判別:Etag/If-None-Match:基於文件的校驗碼來判別;
User-Agent <--> private cache <--> public cache <--> public cache 2 <--> Original Server
Web Page Cache:squid --> varnish varnish官方站點: http://www.varnish-cache.org/
緩存空間耗盡:LRU,最近最少使用;
web后台restful簡單架構模型

應用運維三大日程工作:發布-----變更-----故障處理
程序架構:
Manager進程
Cacher進程,包含多種類型的線程:accept, worker, expiry, ...
shared memory log:統計數據:計數器(處理請求,時間,hit數,miss數);日志區域:日志記錄;
varnishlog, varnishncsa, varnishstat...
配置接口:VCL vcl complier --> c complier --> shared object
varnish的程序環境:
/etc/varnish/varnish.params: 配置varnish服務進程的工作特性,例如監聽的地址和端口,緩存機制;
/etc/varnish/default.vcl:配置各Child/Cache線程的緩存策略;
主程序:/usr/sbin/varnishd
CLI interface:/usr/bin/varnishadm 如varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 (默認6082為varnish管理端口)
Shared Memory Log交互工具:
/usr/bin/varnishhist /usr/bin/varnishlog /usr/bin/varnishncsa /usr/bin/varnishstat /usr/bin/varnishtop
測試工具程序:
/usr/bin/varnishtest
VCL配置文件重載程序:/usr/sbin/varnish_reload_vcl
varnish服務
/usr/lib/systemd/system/varnishlog.service
/usr/lib/systemd/system/varnishncsa.service 日志持久的服務;
varnish工作邏輯
1.varnish配置測試(緩存、自定義非緩存、purge更新緩存、按需調度、負載均衡、健康狀態檢查)
vim /etc/varnish/varnish.params

其中需要把端口改為80 (默認6081),管理地址為本機,管理端口為6082(默認),以varnish身份運行
varnish的緩存存儲機制( Storage Types):
· malloc[,size] 內存存儲,[,size]用於定義空間大小;重啟后所有緩存項失效;一般4G較合適,內存空間有限,且內存碎片會大大影響性能;
· file[,path[,size[,granularity]]] 磁盤文件存儲,黑盒;重啟后所有緩存項失效;
· persistent,path,size 文件存儲,黑盒;重啟后所有緩存項有效;實驗狀態;
緩存處於穩態很難,即緩存熱身時間很長,
該文件最后一行,可靈活自定義

vim /etc/varnish/default.vcl (cat /etc/varnish/default.vcl |egrep "^[^#]")
#必須以vcl git 開頭
vcl 4.0;
#導入directors模塊實現負載均衡;並定義acl,來控制purger(更新緩存)的使用 import directors; acl purgers { "127.0.0.0"/8; }
#健康狀態檢查定義項
probe healthche { .url="/index.html"; .timeout = 2s; .window = 6 ; .threshold = 5; }
#backend組即為后台web端 backend server1 { .host = "172.18.64.7"; .port = "80"; .probe = healthche ; } backend server2 { .host="172.18.64.106"; .port="80"; .probe = healthche ; } }
#以輪詢方式調度 sub vcl_init { new srvs =directors.round_robin(); srvs.add_backend(server1); srvs.add_backend(server2); } sub vcl_recv { # Happens before we check if we have this in cache already. # # Typically you clean up the request here, removing cookies you don't need, # rewriting the request, etc. set req.backend_hint=srvs.backend();
#正則匹配 login或admin隱私信息不允許服務端緩存 if (req.url ~ "(?i)^/(login|admin)") { return(pass); }
#url重寫,告訴后端服務器真實的請求者,安全避免重復添加,還可定義在記錄日志中 if (req.restarts == 0) { if (req.http.X-Fowarded-For) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } }
#purge的使用:更新一個緩存,而更新一組緩存用ban if (req.method == "PURGE"){ if (!client.ip ~ purgers) { return(synth(405,"Purging not allowed for "+client.ip)); } return(purge); } } sub vcl_backend_response { # Happens after we have read the response headers from the backend. # # Here you clean the response headers, removing silly Set-Cookie headers # and other mistakes your backend does.
#客戶端的圖片類信息可以除去cookies標志讓服務器能夠緩存,並定義緩存有效期為2H if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif)$") { unset beresp.http.Set-cookies; set beresp.ttl =7200s; } } sub vcl_deliver { # Happens when we have all the pieces we need, and are about to send the # response to the client. # # You can do accounting or modifying the final object here.
#定義緩存響應頭部 if (obj.hits>0) { set resp.http.X-Cache = "HIT via " + server.ip; } else { set resp.http.X-Cache = "MISS from " + server.ip; } }
varnish_reload_vcl 重新加載后測試效果

F5刷新后。。。(后台web站點172.18.64.7,而varnish端為172.18.64.107,實際生產varnish的vip為公網地址,而rip為局域網地址)

對與login或admin私有信息來說,不能緩存。

F5刷新后,依然無法緩存,且由於調度輪詢則來自另一個web

對於purge的使用,首先定義acl(清緩再熱身存負載大,安全起見必須指定特定主機才有清緩存權)

覆蓋后F5刷新,由於緩存還是原來圖片信息


在acl定義的主機上用purge 更新單個緩存 curl -X PURGE http://127.0.0.1/world.jpg

此時再刷新網頁即可刷新
但purge只能刷新一個資源,且有時會經常出錯一般可在vcl命令行中用ban刷新一類資源
ban req.url ~ (?i).(jpg|jpeg)$
![]()
F5再次刷新(以將圖片替換掉)

再次刷新依然是hit的
對於一般站點來說,css、html、js、txt(升級會變)和圖片(一般不會變)一般分隔開,設定使用多個后端主機:
backend server1 {
.host = "172.18.64.7";
.port = "80";
}
backend server2 {
.host = "172.18.64.106";
.port = "80";
}
#在sub vcl_recv 加
if (req.url ~ "(?i)\.(jpg|jpeg|png)$") {
set req.backend_hint = server2;
} else {
set req.backend_hint = server1;
}
這樣即可把不同資源按需調度到不同主機。
關於負載均衡,最上面的代碼段里import導入相關模塊后,在sub vcl_init 中定義輪詢調度,一般輪詢就夠,因為大多數別CDN擋在外面,剩
下的又有絕大多數別hit中,所以只有很少的請求進入后端主機,此時測試訪問login/login.html那個不允許緩存的文件即可實現輪詢訪問效果。
當然也可基於hash的權重配置,如下基於cookie的session sticky:
sub vcl_init {
new h = directors.hash();
h.add_backend(one, 1); // backend 'one' with weight '1'
h.add_backend(two, 1); // backend 'two' with weight '1'
}
sub vcl_recv {
// pick a backend based on the cookie header of the client
set req.backend_hint = h.backend(req.http.cookie);
}
健康狀態檢測backend.list

最上面的代碼已經實現健康狀態的檢測,也可實現手動健康檢測
backend.set_health server sick | health | auto


但一般會設置為機器檢測狀態

2.varnish優化與管理、監控記錄命令
在線程池內部,其每一個請求由一個線程來處理; 其worker線程的最大數決定了varnish的並發響應能力;
thread_pools:Number of worker thread pools. 最好小於或等於CPU核心數量;
thread_pool_max:The maximum number of worker threads in each pool. 每線程池的最大線程數;
thread_pool_min:The minimum number of worker threads in each pool. 額外意義為“最大空閑線程數”;
最大並發連接數 = thread_pools * thread_pool_max
thread_pool_timeout:Thread idle threshold. Threads inexcess of thread_pool_min, which have been idle for at least this long,
will be destroyed.
thread_pool_add_delay:Wait at least this long after creating a thread.
thread_pool_destroy_delay:Wait this long after destroying a thread.
設置方式:
vcl.param
如 param.set thread_pools 4
param.show thread_pools 可查看
永久有效的方法:
vim /etc/varnish/varnish.params 最后一行
DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"
varnish的幾個命令行工具
varnishlog把每一個請求拆開詳細顯示

varnishtop (Varnish log entry ranking) 則會把varnishlog把請求method按照速率做一個簡單排序

-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同時使用多個-i選項,也可以一個選項跟上多個標簽;
-I <[taglist:]regex> 正則表達式匹配值
-x taglist:排除列表
-X <[taglist:]regex>
varnishstat則會動態顯示

varnishstat - Varnish Cache statistics
-1 -f FILED_NAME 只顯示特定項一次
-l:可用於-f選項指定的字段名稱列表;
MAIN.cache_hit 和MAIN.cache_miss是最常要看的參數
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss顯示指定參數的當前統計數據;
# varnishstat -l -f MAIN -f MEMPOOL 列出指定配置段的每個參數的意義;
varnishncsa - Display Varnish logs in Apache / NCSA combined log format 即按照ncsa格式顯示日志

varnish的訪問日志一般在內存中,容量大概只有80-90M,用不了多久就會被覆蓋,如果不想別覆蓋,可以把varnishncsa當日志服務啟動
systemctl start varnishncsc.service
此時會在/var/log/varnish/目錄下生成varnishncsa文件,此時訪問即可被記錄,但盡量不要開啟這個日志功能!因為作用不是很大,且容易
產生干擾信息,有專門的日志監控服務完成。
3.總結 :varnish: state engine, vcl
varnish 4.0:
vcl_init
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_pipe
vcl_waiting
vcl_purge
vcl_deliver
vcl_synth
vcl_fini
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
sub VCL_STATE_ENGINE {
...
}
backend BE_NAME {}
probe PB_NAME {}
acl ACL_NAME {}
實際生產環境實例
backend imgsrv1 { .host = "192.168.10.11"; .port = "80"; } backend imgsrv2 { .host = "192.168.10.12"; .port = "80"; } backend appsrv1 { .host = "192.168.10.21"; .port = "80"; } backend appsrv2 { .host = "192.168.10.22"; .port = "80"; } sub vcl_init { new imgsrvs = directors.random(); imgsrvs.add_backend(imgsrv1,10); imgsrvs.add_backend(imgsrv2,20); new staticsrvs = directors.round_robin(); appsrvs.add_backend(appsrv1); appsrvs.add_backend(appsrv2); new appsrvs = directors.hash(); appsrvs.add_backend(appsrv1,1); appsrvs.add_backend(appsrv2,1); } sub vcl_recv { if (req.url ~ "(?i)\.(css|js)$" { set req.backend_hint = staticsrvs.backend(); } if (req.url ~ "(?i)\.(jpg|jpeg|png|gif)$" { set req.backend_hint = imgsrvs.backend(); } else { set req.backend_hint = appsrvs.backend(req.http.cookie); } }
