Linux自學筆記——varnish
緩存:緩存就是數據交換的緩沖區(cache),當某一硬件要讀取數據時,會首先從緩存中查找需要的數據,如果找到了則直接執行,找不到的話則從內存中找。由於緩存的運行速度比內存快很多,故緩存的作用就是幫助硬件更快的運行。
程序具有局部性:時間局部性,空間局部性。
緩存存儲方式:key-value
Key:訪問路徑,url,hash
Value:web content
熱點數據:局部性的數據;
命中率:hit/(hit+miss)
文檔命中率:從文檔個數進行衡量;
字節命中率:從內容大小進行衡量
註意:
緩存對象:生命周期;定期清理;
緩存空間耗盡:LRU(最近最少使用)
可緩存,不可緩存(用戶私有數據)
緩存處理的步驟:
接收請求 à 解析請求(提取請求的URL及各種首部)à 查詢緩存 à 新鮮度檢測 à 創建響應報文 à 發送響應 à 記錄日誌
新鮮度檢測機制:
過期日期:
HTTP/1.0 Expires
Expires
HTTP/1.1 Cache-Control:max-age
Cache-Control:max-age=600
有效性再驗證:revalidate
如果原始內容未改變,則僅響應首部(不附帶body部分),響應碼304(Not modified)
如果原始內容發生改變,則正常響應 , 響應碼為200;
如果原始內容消失,則響應404,此時緩存中的cache object也應該被刪除;
條件式請求首部:
If-Modified-Since:基於請求內容的時間戳驗證;
If-Unmodified-Since
If-Match:
If-None-Match:
Etag: faiy89345
常用的開源解決方案:squid ,varnish,本文重點介紹varnish;
Varnish:
程序架構圖:
管理進程:編譯vcl並應用新配置;監控varnish;初始化varnish;CLI接口
Child/cache:
Acceptor:接收新的連接請求;
worker threads:處理用戶請求;
Expiry:清理緩存中的過期對象;
日誌:Shared Memory Log,共享內存日誌大小默認一般為90MB,分為兩部分,前一部分為計數器,後一部分請求相關數據;
vcl:Varnish Configuration Language
保存策略配置接口;
基於“域”的簡單編程語言;
內存分配和回收:
malloc(),free()
varnish如何存儲緩存對象?可以通過以下三種方式;
file:單個文件;不支持持久機制;
malloc:內存
persistent:基於文件的持久存儲;
varnish的主要配置文件及工具:
配置varnish的三種應用:
1. Varnish應用程序的命令行參數;
監聽的socket,使用的存儲類型等等;額外的配置參數;
-p parm=value
-r param,param,…:設定只讀參數列表;
/etc/varnish/varnish.params
2. –p選項指明的參數:
運行時參數:
也可在程序運行中,通過其CLI進行配置;
3. vcl:配置緩存系統的緩存機制;
通過vcl配置文件進行配置;
先編譯,後應用;
依賴於c編譯器;
Note:
1) varnish是一個web代理緩存服務器,既然是代理就要代表原始web服務器工作,所以,接收的用戶請求會首先發送到varnish,那這樣一來按理說就應該監聽在80端口;其實不然,為了防止和本機的80端口起沖突,varnish默認是監聽在6081端口的;這是因為雖然varnish為代理緩存服務器,但並不會讓其直接面向用戶,而是通過前端的nignx或者haproxy將用戶的請求反代至varnish,由varnish完成緩存管理,如果本地緩存沒有,varnish再去查找原始服務器,如果有就直接返回給前端反代服務器。
2) 6082端口為基於命令行工具去管理和控制varnish的接口,為了安全起見監聽在本機的127.0.0.1的地址;
演示:使用varnish代理緩存後端web服務
實驗環境:兩臺服務器,一臺作varnish代理緩存服務器,一臺作後端服務器;
Ip地址分配:
varnish緩存服務器:192.168.19.203
後端RS:192.168.19.143
1. 配置文件/etc/varnish/varnish.params如下,(一般默認不改變)
2. 編輯/etc/varnish/default.val文件,反向代理至後端服務器;
3. 啟動varnish服務並查看端口;
4. 訪問網站測試;
Note:後面需要加端口6081,
命令行工具:
varnishadm命令以及vcl配置文件的重載:
重載vcl配置文件:
varnish_reload_vcl
varnishadm命令:
varnishadm -S /etc/varnish/secret -T IP:PORT
vcl:
請求流程圖:
state engine:各引擎之間存在一定程度上的相關性;前一個engine如果可以有多種下遊engine,則說明engine需要用return指明要轉移的下遊engine;
vcl_recv
vcl_hash
vcl_hit
vcl_miss
vcl_fetch
vcl_deliver
vcl_pipe
vcl_pass
vcl_error
編程語言語法:
1) //,#,/* */用於註釋;會被編譯器忽略;
2) sub $name:用於定義子例程;
sub vcl_recv {
}
3) 不支持循環;
4) 有眾多內置的變量,變量可調用位置與state engine有密切相關性;
5) 支持終止語句,return(action):沒有返回值;
6) 域專用 ;
7) 操作符:=,==,~,!,&&,||
條件判斷語句:
if (CONDTION) {
} else {
}
變量賦值:set name=value
unset name
req.http.HEADER:調用request報文中http報文中http協議的指定的HEADER首部
req.http.X-Forwarded-For
req.http.Auhtorization
req.http.cookie
req.request:請求方法
client.ip:客戶端IP;
state engine workflow(v3):
vcl_recv --> vcl_hash --> vcl_hit --> vcl_deliver
vcl_recv --> vcl_hash --> vcl_miss --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pass --> vcl_fetch --> vcl_deliver
vcl_recv --> vcl_pipe
state engine(v4)
vcl_recv
vcl_pass
vcl_pipe
vcl_hash
vcl_hit
vcl_miss
vcl_backend_fetch
vcl_backend_response
vcl_backend_error
vcl_purge
vcl_synth
https://www.varnish-software.com/book/4.0/chapters/VCL_Basics.html
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
定義在vcl_deliver中,向響應給客戶端的報文添加一個自定義首部X-Cache
if (obj.hits>0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cahce = "MISS";
}
演示:通過判斷想應報文緩存命中的次數來判斷是否命中緩存;
1) 編輯配置文件/etc/varnish/default.vcl;
2) 重載配置文件,過程如下;
3) 瀏覽器測試;
Varnish中的內置變量:
變量種類:
client
erver
req
resp
bereq
beresp
obj
storage
bereq
bereq.http.HEADERS: 由varnish發往backend server的請求報文的指定首部;
bereq.request:請求方法;
bereq.url:
bereq.proto:協議的版本
bereq.backend:指明要調用的後端主機;
beresp
beresp.proto:後端服務器響應的協議版本
beresp.status:後端服務器的響應的狀態碼
beresp.reason:原因短語;
beresp.backend.ip:後端響應的ip
beresp.backend.name:BE主機的主機名
beresp.http.HEADER: 從backend server響應的報文的首部;
beresp.ttl:後端服務器響應的內容的余下的生存時長;
obj
obj.ttl: 對象的ttl值;
obj.hits:此對象從緩存中命中的次數;
server
server.ip
server.hostname
req
resp
演示1:強制對某類資源的請求不檢查緩存,之類以login和admin為例;
1) 提供測試頁面環境;
2) 訪問測試;
可以看出,第一次沒有命中,但是以後都能命中的。
3) 現在我們修改配置文件,在vcl_recv下添加以下內容,強行對此資源不檢查緩存;
4) 重新裝載配置文件,測試(裝載配置文件過程,這裏不再多說)
可以看出,這兩次訪問,都沒有擊中緩存;
演示2:設定多個後端主機,並分別以負載均衡和動靜分離的方式調度;
動靜分離方式調度:
1) 提供RS2的php頁面測試環境;(註意,要安裝httpd+php)
2) 編輯配置文件,添加內容如下;
3) 重載配置文件,並測試;
訪問.php文件時:
Note:php右上角的圖片沒有顯示出來,是因為靜態資源發往了192.168.19.144這臺主機,而這臺主機上又沒有這張圖片。所以顯示不出來;
訪問html文件時:
負載均衡調度:使用前需要導入:import director
1) 編輯配置文件,首先導入import director模塊,內容如下;
2) 重載配置文件,測試;
Note:varnish的負載均衡調度是對請求的不同資源的負載均衡調度,請求統一資源,它只會調度至一開始調度的服務器;
定義健康狀態監測;
backend server的定義:
backend name {
.attribute = "value";
}
.host: BE主機的IP;
.port:BE主機監聽的PORT;
.probe: 對BE做健康狀態檢測;
.max_connections:並連接最大數量;
後端主機的健康狀態檢測方式:
probe name {
.attribute = "value";
}
.url: 判定BE健康與否要請求的url;
.expected_response:期望響應狀態碼;默認為200;
.request:發出的具體請求
.window:基於最近的多少次檢查來判斷其健康狀態;
.threshhold:最近.window中定義的這麽多次檢查中至有.threshhold定義的次數時成功的;
.interval:監測額度;
.timeout:超時時長;
演示3:設定varnish對後端主機做健康狀態監測;
1) 使用varnishadm命令可以查看後端主機是否做了檢測狀態監測;
2) 編輯配置文件/etc/varnish/default.vcl,定義健康狀態監測的probe;
方法一:
方法二:
3) 重載配置文件,查看後端主機是否開啟健康狀態檢測;
4) 瀏覽器訪問測試看是否能正常訪問;
補充:
移除單個緩存對象
purge用於清理緩存中的某特定對象及其變種(variants),因此,在有著明確要修剪的緩存對象時可以使用此種方式。HTTP協議的PURGE方法可以實現purge功能,不過,其僅能用於vcl_hit和vcl_miss中,它會釋放內存工作並移除指定緩存對象的所有Vary:-變種,並等待下一個針對此內容的客戶端請求到達時刷新此內容。另外,其一般要與return(restart)一起使用。
下面是個在VCL中配置的示例。
acl purgers {
"127.0.0.1";
"192.168.0.0"/24;
}
sub vcl_recv {
if (req.request == "PURGE") {
if (!client.ip ~ purgers) {
error 405 "Method not allowed";
}
return (lookup);
}
}
sub vcl_hit {
if (req.request == "PURGE") {
purge;
error 200 "Purged";
}
}
sub vcl_miss {
if (req.request == "PURGE") {
purge;
error 404 "Not in cache";
}
}
sub vcl_pass {
if (req.request == "PURGE") {
error 502 "PURGE on a passed object";
}
}
客戶端在發起HTTP請求時,只需要為所請求的URL使用PURGE方法即可,其命令使用方式如下:
# curl -I -X PURGE http://varniship/path/to/someurl
補充資料:
varnish的線程模型:
cache-worker線程
cache-main線程:此線程只有一個,用於啟動caceh;
ban luker:
acceptor:
epoll:線程池管理器
expire:清理過期緩存
varnish定義其最大並發連接數:線程池模型:
thread_pools:線程池個數;默認為2;
thread_pool_max:單線程池內允許啟動的最多線程個數;
thread_pool_min
thread_pool_timeout:多於thread_pool_min的線程空閑此參數指定的時長後即被purge;
varnish的param查看及改變:
param.show [-l] [param]
param.set [param] [value]
varnish的命令行工具:
varnishadm,
varnishtop: 內存日誌區域查看工具
RxHeader User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36
其中:
RxHeader:稱為tag, 基於tag過濾,可使用-i或-x選項;
User-Agent起始的內容:稱為日誌信息,可使用-I或-X選項進行過濾;
-I regexp: 僅顯示被模式匹配到的條目
-X regexp:僅顯示不被模式匹配到的條目
-C: 忽略字符大小寫;
-d: 顯示已有日誌;
varnishstat:
-f field, field, ...
-l: 列出所有可用字段
-x: xml輸出格式
-j: json輸出格式
varnishlog, varnishncsa
Linux自學筆記——varnish