Varnish是一款高性能、開源的反向代理服務器和緩存服務器。Varnish使用內存緩存文件來減小響應時間和網絡帶寬消耗。這個項目是由挪威的一家報紙Verdens Gang的網絡分支起始的,其架構設計和開發總監Poul-Henning Kamp是FreeBSD核心的開發人員之一,最初項目的管理與基礎設施及額外開發由挪威一家Linux諮詢公司Linpro提供。php
說到varnish,squid就不得不說起。squid算得上是古老的緩存服務器。因爲varnish先進的設計理念,性能要比squid高上許多,varnish還能夠經過端口進行管理,使用正則語句作到清除指定緩存的功能,這些squid都作不到。可是varnish在高併發的狀況下,資源消耗較高,並且varnish服務進程一旦崩潰,重啓,內存中的緩存數據將所有丟失。css
varnish是基於現代設備設計的服務項目,因此僅支持64位系統。Manager Process 負責處理請求任務,保證每一個任務分配一個worker threads。因此varnish是一個重線程型服務。除此以外,manager process 包含接受CLI命令控制的功能,包括調整運行參數,vcl配置更新。初始化子進程Cacher Process,並按必定頻率檢測cacher在線與否。html
Cacher Process 功能:前端
varnish使用工做空間減小每一個線程須要請求或者修改內存時發生的爭搶。varnish具備多個工做空間,最爲重要的是 session 工做空間,用來維護session 相關數據。express
在日誌記錄方面,Cacher process 使用VSL 機制來處理,這是一個共享內存空間,能夠有效減小記錄阻塞。日誌空間分爲兩個部分,分別記錄格式化的請求日誌,以及計數器數值。能夠經過varnish自帶log工具進行查看,分析或者永久存儲日誌。apache
2.1 malloc[,size]
調用malloc(),爲緩存分配內存空間,此種方式不可避免地會產生碎片文件,額外佔用內存後端
[,size]用於定義空間大小;重啓後全部緩存項失效;瀏覽器
2.2 file[,path[,size[,granularity]]]
varnish建立一個文件用來存儲緩存數據,而後將此文件映射到內存空間中,可是該文件並不會持久保存數據,重啓後全部緩存項失效;緩存
granularity 遞增大小服務器
2.3 persistent,path,size
持久文件存儲,黑盒;重啓後全部緩存項有效;可是處於實驗階段,問題較多;
2.4 MSE
Massive Storage Engine,在plus版可用,意味着收費。該模式設計的容量巨大可達100TB,磁盤性能要優於file模式。
總結:當內存空間不足以存儲全部緩存數據時,應選擇file 或 mse 存儲。因此通常配置成file存儲,固然付費的話使用mse更佳。
本文主機環境爲CentOS7.2,Varnish 版本 4.0
varnish的程序環境:
/etc/varnish/varnish.params: 配置varnish服務進程的工做特性,例如監聽的地址和端口,緩存機制;
/etc/varnish/default.vcl:配置各Child/Cache線程的工做屬性;
主程序:
/usr/sbin/varnishd
CLI interface:
/usr/bin/varnishadm
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
Systemd Unit File:
/usr/lib/systemd/system/varnish.service #varnish服務
/usr/lib/systemd/system/varnishlog.service #logger daemon
/usr/lib/systemd/system/varnishncsa.service #lgger daemon in apache format
systemd方式啓動varnish 服務,主程序指定的配置文件爲:/etc/varnish/varnish.params
-a address[:port][,address[:port][...],默認爲6081端口; #對客戶端開放的監聽端口地址
-T address[:port],默認爲6082端口; #管理工具鏈接的端口地址
-s [name=]type[,options],定義緩存存儲機制; #能夠屢次定義此項
-u user
-g group
-f config:VCL配置文件;
-F:運行於前臺;
...
線程相關的參數:
在線程池內部,其每個請求由一個線程來處理; 其worker線程的最大數決定了varnish的併發響應能力;
thread_pools:Number of worker thread pools. 線程池數量,默認值爲2,官方介紹2個線程池已足夠用,再增長該數值沒有提高效果;
thread_pool_max:The maximum number of worker threads in each pool.每一個線程池建立最大線程的數量;默認5000
thread_pool_min:The minimum number of worker threads in each pool. 每一個線程池保持最少線程的數量;額外意義爲「最大空閒線程數」;默認100
因此咱們常常須要調整的參數就是thread_pool_max,thread_pool_min
計算varnish最大併發鏈接數=thread_pools * thread_pool_max
thread_pool_timeout: 線程空閒時間,超過閾值則摧毀線程
thread_pool_add_delay:建立一個新線程的延遲時間,默認值爲0s
thread_pool_destroy_delay:摧毀一個線程的延遲時間,默認值爲2s;
設置方式:
運行動態修改經過varniadm接口設置
命令:param.set
永久有效的方法:
運行時參數:/etc/varnish/varnish.params文件, DEAMON_OPTS
-p param=value:設定運行參數及其值; 可重複使用屢次;
-r param[,param...]: 設定指定的參數爲只讀狀態
例如: DAEMON_OPTS="-p thread_pool_min=2 -p thread_pool_max=10000 -p thread_pool_timeout=300"
用法:varnishadm -S /etc/varnish/secret -T [ADDRESS:]PORT
指定了鏈接密鑰,安裝varnish時生成的。指明管理接口的端口地址,默認爲127.0.0.1 可省略。
進入以後,輸入help [command] 獲取幫助
梳理經常使用指令
配置文件相關:
vcl.list :查看vcl 列表
vcl.load:裝載,加載並編譯;
vcl.use:激活;
vcl.discard:刪除;
vcl.show [-v] <configname>:查看指定的配置文件的詳細信息;-v 選項查看默認vcl代碼
運行時參數:
param.show -l:顯示列表;
param.show <PARAM>
param.set <PARAM> <VALUE> 設定參數
緩存存儲:
storage.list
後端服務器:
backend.list
Varnish Configuration Language (VCL) 是一種動態語言,用來描述請求處理和制定緩存策略。vcl配置內容由manager process 建立的VCC子進程轉換成C語言代碼,再經由gcc編譯成共享對象,最後裝載到cacher process中生效。
想要寫好vcl配置,須要瞭解varnish內部報文的處理流程,其核心關鍵詞是 finite state machine——有限狀態引擎。下圖爲簡單的處理流程:
圖中橢圓中表明狀態引擎。這些狀態引擎被概念化後成爲vcl中的子函數,以vcl_前綴開頭,在引擎中,能夠對每一個請求中的http 首部或者其餘各方面的內容進行檢查或者修改操做。return(action)代碼表示中斷一個狀態,其中action是vcl關鍵字,用來指向下一步去向哪一個狀態引擎。
每一個請求都被單獨分開處理;狀態之間存在相關性,但彼此間互相隔離。
在下一步瞭解vcl 配置代碼以前,先了解一下vcl背後的基礎概念。當varnish處理一個請求時,首先要解析這個請求。從http 首部中分析出請求的方法類型,判斷是否爲有效的請求方法等等,當基礎解析完成以後,依據第一個策略進行檢查進而作出判斷。vcl就是根據由各個策略組成的規則來進行各類動做。
上圖可分爲兩個區域:前端frontend和後端backend
前端狀態可分爲四個階段:
第一階段:
vcl_recv #接受客戶端請求,進行判斷
第二階段:
vcl_hash #進行hash計算,不進行判讀處理,計算以後送往各個第三階段狀態引擎中
第三階段:
vcl_hit #緩存命中,到此處理
vcl_pass #緩存跳過
vcl_miss #緩存未命中
vcl_purge #清理緩存
vcl_pipe #對於沒法識別的http首部請求直接送入管道,交由後端處理再也不處理
第四階段:
vcl_deliver: 大部分響應客戶端的請求由此發送回去
vcl_synth:接受來自vcl_purge的任務,對於指定的緩存,進行刪除處理
後端狀態分爲兩階段:
第一階段:
vcl_backend_fetch:接受來自前端狀態vcl_pass或vcl_miss 的任務,向後端主機請求
第二階段:
vcl_backend_response:接受到後端返回正常狀態報文,進行是否緩存檢查,須要緩存的響應將其緩存,不須要則不緩存,最後送到vcl_deliver
vcl_backend_error:後端主機錯誤,返回錯誤響應
除此以外還有兩個特殊狀態引擎:
vcl_init:在處理任何請求以前要執行的vcl代碼:主要用於初始化VMODs;
vcl_fini:全部的請求都已經結束,在vcl配置被丟棄時調用;主要用於清理VMODs;
一個大前提:varnish 4.0版本開始,vcl擁有本身的默認規則,它不可移除,老是追加在自定義的規則以後。
(1) vcl配置文件以 vcl 4.0 開頭;
(2) C語言註釋風格://, # and /* foo */ ;
(3) 子函數使用sub關鍵字聲明, 例如sub vcl_recv { ...};
(4) 無循環, state-limited variables(受限於引擎的內建變量);
(5) 使用return(action)中斷引擎狀態,指向下一步處理,action爲關鍵字 ,例如: return(pass);
(6) 可動態裝載;
sub subroutine {
...
}
if CONDITION {
...
} else {
...
}
return(), hash_data()
函數:
hash_data():指明哈希計算的數據;減小差別,以提高命中率;
regsub(str,regex,sub):把str中被regex第一次匹配到字符串替換爲sub;主要用於URL Rewrite
regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替換爲sub;
return():
ban(expression)
ban_url(regex):Bans全部的其URL能夠被此處的regex匹配到的緩存對象;
synth(status,"STRING"):purge操做;
關鍵字:
call subroutine, return(action),new,set,unset
下圖爲指定函數智能用於特定子函數中
操做符:
==, !=, ~, >, >=, <, <=
邏輯操做符:&&, ||, !
變量賦值:=
正則匹配:~
(?i) 表示忽略大小寫
同時注意匹配的規則若是是字符串須要" " 引發
內建變量:
req.*:request,表示由客戶端發來的請求報文相關;
req.http.*
req.http.User-Agent, req.http.Referer, ...
bereq.*:由varnish發往BE主機的httpd請求相關;
bereq.http.*
beresp.*:由BE主機響應給varnish的響應報文相關;
beresp.http.*
resp.*:由varnish響應給client相關;
obj.*:存儲在緩存空間中的緩存對象的屬性;只讀;
經常使用變量:
bereq.*, req.*:
bereq.http.HEADERS
bereq.request:請求方法;
bereq.url:請求的url;
bereq.proto:請求的協議版本;
bereq.backend:指明要調用的後端主機;
req.url:請求的url
req.http.Cookie:客戶端的請求報文中Cookie首部的值;
req.http.User-Agent:瀏覽器類型
beresp.*, resp.*:
beresp.http.HEADERS
beresp.status:響應的狀態碼;
reresp.proto:協議版本;
beresp.backend.name:BE主機的主機名;
beresp.ttl:BE主機響應的內容的餘下的可緩存時長;
obj.*
obj.hits:此對象從緩存中命中的次數;
obj.ttl:對象的ttl值
server.*
server.ip
server.hostname
client.*
client.ip
同時注意變量是受狀態限制的,下圖爲可用表
用戶自定義:
set variable=value #定義變量
unset variable #撤銷定義的變量
~]$ vi /etc/varnish/default.vcl
sub vcl_deliver { if ( obj.hits>0 ) { set resp.http.X-cache = " HIT via " + server.ip; } else { set resp.http.X-cache = " MISS via "+ server.ip; } }
~]$ varnish_reload_vcl #重載vcl
或者 使用varnishadm 進入管理接口,使用以下命令
~]$ vcl.load test1 default.vcl #裝載vcl,並指定一個命名test1
若是返回狀態碼200,則語法正確,編譯經過
~]$ vcl.use test1 #以下圖所示vcl新配置已生效
使用curl命令測試,第一次無緩存,則未命中
第二次訪問,已有緩存,則命中
設定訪問/login 或 /admin 下的目錄任何文件都不查詢緩存
vcl_recv { if (req.url ~ "(?i)^/(login|admin/)") { return(pass); } }
sub vcl_backend_response {
if (beresp.http.cache-control !~ "s-maxage") { if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") { unset beresp.http.Set-Cookie; set beresp.ttl = 3600s; } }
}
(1) 能執行purge操做
sub vcl_purge {
return (synth(200,"Purged"));
}
(2) 什麼時候執行purge操做
sub vcl_recv {
if (req.method == "PURGE") {
return(purge);
}
...
}
上面的定義比較簡單,任何人均可以對cache作清理操做,下面則根據IP地址作出限制
添加此類請求的訪問控制法則:
acl purgers {
"127.0.0.0"/8;
"10.1.0.0"/16;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purgers) { #這裏正則匹配的時acl列表,不須要引號
return(synth(405,"Purging not allowed for " + client.ip)); #來自不屬於acl定義的purgers組的purge請求則返回錯誤代碼
}
return(purge);
}
...
}
backend default {
.host = "172.16.100.6";
.port = "80";
}
backend appsrv {
.host = "172.16.100.7";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "(?i)\.php") {
set req.backend_hint = appsrv; #php資源轉發至appsrv處理
} else {
set req.backend_hint = default;
}
...
}
使用前須要在vcl配置中導入模塊:
import director;
示例:
import directors; # load the directors
backend server1 {
.host =
.port =
}
backend server2 {
.host =
.port =
}
sub vcl_init { #在init 子函數中定義
new GROUP_NAME = directors.round_robin(); #建立組,並命名爲GROUP_NAME,指定調度方法
GROUP_NAME.add_backend(server1); #爲組添加服務器成員
GROUP_NAME.add_backend(server2);
}
sub vcl_recv {
# send all traffic to the bar director:
set req.backend_hint = GROUP_NAME.backend(); #組引用方法
}
varnish能夠對後端主機進行健康檢測,動態進行移除或恢復後端主機調度列表
.probe:定義健康狀態檢測方法;
.url:檢測時請求的URL,默認爲"/";
.request:發出的具體請求;
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close"
.window:基於最近的多少次檢查來判斷其健康狀態;
.threshhold:最近.window中定義的這麼次檢查中至有.threshhold定義的次數是成功的;
.interval:檢測頻度;
.timeout:超時時長;
.expected_response:指望的響應碼,默認爲200;
健康狀態檢測的配置方式:
(1) probe PB_NAME = { }
backend NAME = {
.probe = PB_NAME;
...
}
(2) backend NAME {
.probe = {
...
}
}
示例:
probe check { #probe 先定義好
.url = "/.healthcheck.html";
.window = 5;
.threshold = 4;
.interval = 2s;
.timeout = 1s;
}
backend default {
.host = "10.1.0.68";
.port = "80";
.probe = check; #引用檢測方式
}
backend appsrv {
.host = "10.1.0.69";
.port = "80";
.probe = check;
}
在varniadm 命令接口中查看檢測情況
用來查看 shared memory log 日誌工具
默認爲動態刷新顯示方式
選項
-1 打印當前統計結果
-f FILED_NAME 顯示指定字段的統計
-l:可用於-f選項指定的字段名稱列表;
example:
# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
默認動態更新
選項:
-1 打印當前排名
-i taglist 顯示指定字段排名。能夠同時使用多個-i選項,也能夠一個選項跟上多個標籤 ","分隔;
-I <[taglist:]regex> 基於正則顯示字段
-x taglist:排除列表
-X <[taglist:]regex> 基於正則排除字段
顯示share memory 中的日誌記錄
顯示share memory 中的日誌記錄,apache日誌形式
本文到此結束
完