第二篇 varnish
一、http緩存機制詳解
作爲替代squid緩存工具的存在。
連接接口:cli、telnet、web方式
1、 web常見架構模型
c/s架構(http協議):
user agent:elinks curl、ab、http_load、spider、網絡爬蟲
b/s架構browser/server(只需要客戶端瀏覽器即可完成很多需要第三方軟件纔可以完成工作。比如在線linux、在線office、網頁遊戲等就是b/s架構)
2、緩存分類
私有緩存:
存在於客戶端瀏覽器,通常關閉瀏覽器後刪除
公共緩存:
正向代理服務器:接近於客戶端(客戶端局域網),代理用於訪問網站,通常是客戶端的網關地址,也可以只設置瀏覽器的代理功能。透明代理(trunning proxy)需要將客戶機的網關指向代理服務器,然後代理服務器通過自身設置將客戶端請求轉發給實際web服務器的情況。
反向代理服務器:接近於web服務器端,爲客戶端請求提供解析、負載均衡、緩存功能。當反向代理服務器接近客戶端的時候,就已經是CDN的技術範圍了,這裏就需要智能DNS技術啦。而CDN實質實質上就是指緩存服務器之間的緩存共享,以及同級別緩存之間的自動路由功能,這種依據內容進行的路由就是內容分發網絡CDN啦,而實現這種技術緩存服務器之間要通過CDP協議進行通信和路由。
3、緩存時效機制
由於原始服務器上的數據可能會變化,所以會有緩存時效的情況。最簡單的緩存控制時效是在服務器端自行完成的。http1.0的管理手段很簡單,主要是通過expire來定義。並且在緩存過期後重新發起請求,而不管這個緩存是否還有效。
而1.1增加了緩存檢測機制,取消了exprie機制,客戶端通過發送條件式請求來判斷緩存是否還有效,減少了重傳次數。
cache control
max-age這種相對時長來解決了不同客戶機和服務器之間存在時差的問題。
Etag/if-none-match:通過生成隨機ID號給客戶端,來解決頻繁的數據更新的情況。
HTTP首部控制緩存失效功能:
1、expires:提供指定某web對象的過期時間,常用於純靜態內容緩存。
2、cache-control:用於定義所有的緩存機制都必須遵循的緩存指示,並且它設置的時間會覆蓋expire設置的時間,如public、private、no-cache
etag:響應首部,用於在響應首部報文中爲某web資源定義版本標識符
last-modified:響應首部,用於迴應客戶端關於last-modified-since或者if-none-match首部的請求,通知客戶端其請求的web對象最近的修改時間。
if-modified-since:條件式請求首部,如果在此首部指定的時間後其請求的web內容發生了更改,則服務器響應更改後的內容。否則響應304.
if-none-match:條件式請求首部,web服務器爲其web內容定義了etag首部,客戶端請求時能獲取並保存這個首部的值;而後在後續的請求中通過if-none-match首部附加其認可的標籤列表並讓服務器檢查器原始內容是否有可以和此列表中的某個標籤匹配的標籤,如果有,則相應304,沒有就返回原始內容。
vary:響應首部,原始服務器根據請求來源的不同響應的可能會有所不同的首部,最常見的是vary:accept-encoding,用於通知緩存機制其內容看起來可能不同於用戶請求時accept-encoding-header首部格式
常見的緩存服務器:
squid:適用於重量級大併發的環境,穩定性強
varnish:靈活小巧,適用於輕量級環境
二、varnish
同memcached的最大區別
varnish是開源的反向代理服務器,但最大應用還是緩存功能,所以從根本上講工作在web服務器之前提供緩存功能的服務器都具備反向代理的功能,就像nginx、haproxy都具有緩存功能,但是它們的主要作用卻是反向代理和負載均衡。
所以和memcached的最大區別就是varnish工作在網橋模式下,而memcached工作在旁路模式。
1、特點
緩存可以工作在內存中,也可以工作在磁盤(ssd固態)上,但是並不永久保存數據
支持VCL,varnish configureation language專用的編程語言。所以vcl編寫的代碼需要編譯成c代碼,所以需要gcc程序。
日誌默認保存在內存中,並輪轉替換使用。
2、軟件架構
management:主進程
提供了接口:cli interface
telnet interface
web interface
管理子進程
初始化工作
VCL編譯及檢測功能
配置哪些對象可以緩存
上游服務器有哪些
算法及負載均衡
child/cache:子進程
日誌管理(內存管理)
命令行接口
緩存管理及hash表
接受請求
後端web通信
緩存對象失效管理
工作線程管理
3、varnish的狀態引擎:
用於檢測上游web服務器中的響應報文和客戶端的請求報文內容,並依次判斷作何操作的引擎,通常是在幾個狀態上設置規則並進行檢測處理機制。
基本工作流程:
varnish開始處理一個請求時,首先分析http請求自身,比如從首部獲取請求方法,驗證其是否是一個合法的請求等。當這些基本的分析結束後就西藥做出第一個決策,就是varnish是否從緩存中查找請求的資源,這個決定的實現需要VCL來完成,簡單說,要由VCL-recv方法來完成。如果管理員沒有自定義VCL-recv函數,varnish將會執行默認的vcl-recv函數,但是官方建議用默認的vcl-recv函數。然後返回到主引擎,並有主引擎決定請求的走向。
子例程通過return()將執行結果返回給varinish主進程,並有主進程判斷下一步操作發往何處。
9種狀態:
(1)vcl-recv:
(2)vcl-hash:直接查緩存
(3)vcl-pipe:不查緩存創建專用通道
(4)vcl-pass:不查緩存交給fetch直接到後端查找
(5)vcl-hit:vcl-hash查詢結果,緩存命中
(6)vcl-miss:vcl-hash查詢結果,未命中
(7)vcl-fetch:未命中後由fetch交到後端查詢
(8)vcl-deliver:後端查詢結果回送給客戶端
(9)vcl-error:直接創建錯誤響應報文並返回給客戶端
引擎講解
VCL-RECV:varnish完成對請求報文的解碼爲基本數據結構後要執行的第一個子例程
(1)修改客戶端數據以減少緩存對象的差異
(2)基於客戶端數據選用緩存策略
(3)爲web應用程序執行URL重寫規則
(4)挑選合適的後端web服務器
操作指令
(1)pass:繞過緩存,不從緩存中查詢內容或者不講內容緩存存儲起來
(2)pipe:不對客戶端進行檢查或做出任何任何操作,而是在客戶端和後端web之間建立專用“隧道”。
(3)error:又varnish自己合成一個響應報文,一般是錯誤類消息、重定向信息。
(4):lookup:在緩存中查找用戶請求的數據,如果沒有,後續操作可能會將請求的對象緩存下來。
VCL-RECV的安全緩存策略:
(1)僅處理可以識別的http方法,並且只緩存get或head方法
(2)不緩存任何用戶特有的數據
三、VCL語法
1、//、#、/*comment*/用於註釋
2、sub $name 定義函數
3、不支持循環、有內置變量
4、使用終止語句,沒有返回值
5、域專用
6、操作符:=(賦值)、==(等值比較)、~(匹配模式)、!(取反)、&&(邏輯與)、||(邏輯或)
四、VCL內置函數
1、regsub(str,regex,sub)、regsuball(str,regex,sub)基於正則表示式搜索指定的字符串並替換爲指定的字符串。regsuball可以將str中能夠被regex匹配到的字符串統統替換成sub,而regsub只替換一次
2、return():當某VCL域運行結束時將控制權返回給varnish,並指示varnish如何進行後續的動作,返回的指令包括(lookup、pass、pipe、hit_for_pass、fetch、deliver、hash等)
3、ban(expresssion)
4、purge:從緩存中挑出對某對象及相關變種一併刪除。
5、return(restart):重新運行整個VCL,即重新從vcl-recv開始進行處理,每一次重啓都會增加req.restarts變量的值,max_restarts用來限制最大啓動次數。
6、hash_data(str)
7、ban_url(regex):bans所有其URL能夠由regex匹配的緩存對象
五、varnish的後端存儲(緩存存儲)
-s選項指定存儲類型
file:使用特定的文件存儲全部的緩存數據,並通過mmap()系統調用將其映射到內存
malloc:使用malloc()庫調用在varnish啓動時向操作系統申請指定大小的內存來存儲緩存對象
persistent:和file功能相同,可以持久存儲數據,測試階段
緩存命中率:
文檔命中率
字節命中率
六、varnish安裝
[[email protected] ~]# yum install varnish
==============================================================================================================================================================================================================================================
Package Arch Version Repository Size
==============================================================================================================================================================================================================================================
Installing:
varnish x86_64 2.1.5-6.el6 epel 264 k
Installing for dependencies:
jemalloc x86_64 3.6.0-1.el6 epel 100 k
varnish-libs x86_64 2.1.5-6.el6 epel 90 k
Transaction Summary
==============================================================================================================================================================================================================================================
Install 3 Package(s)
安裝目錄內容:
/etc/rc.d/init.d/varnishlog //實現日誌存儲必須開啓此服務
/etc/rc.d/init.d/varnish //varnish啓動服務
/etc/varnish //配置文件目錄
/var/log/varnish //日誌存儲位置
/etc/sysconfig/avrnish //varnish自身軟件工作特性
/etc/varnish/default.vcl //緩存,引擎配置文件
配置文件基本管理
/etc/sysconfig/varnish
NFILES=131072 最大連接數56535*2
MEMLOCK=82000 varnish內存使用空間大小
RELOAD_VCL=1 不用重啓就可重新編譯並載入VCL
NPROCS="unlimited"
VARNISH_VCL_CONF=/etc/varnish/default.vcl 默認啓動的vcl配置文件
VARNISH_LISTEN_PORT=6081 默認監聽端口,建議是80,對於後端的服務
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 表示本地監聽
VARNISH_ADMIN_LISTEN_PORT=6082 管理端口
VARNISH_SECRET_FILE=/etc/varnish/secret 認證祕鑰文件
VARNISH_MIN_THREADS=1 最小線程數
VARNISH_MAX_THREADS=1000 最大線程數
VARNISH_THREAD_TIMEOUT=120 線程超時時間
VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin 以文件方式緩存數據
VARNISH_STORAGE_SIZE=1G 文件緩存大小
VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}” 以文件方式緩存數據
#VARNISH_malloc_STORAGE_SIZE=1G 內存緩存大小
#VARNISH_STORAGE=“malloc,${VARNISH_malloc_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}"
登錄管理後臺:
[[email protected] ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
七、配置varnish及VCL
1、創建後端服務器(default.vcl)
2、重新加載vcl配置文件,並使用新的編譯文件
vcl.load default1 /etc/varnish/default.vcl 重新加載
200 13
VCL compiled.
vcl.list 查看當前可用的配置vcl
200 50
active 1 boot
available 0 default1
vcl.use default1 使用指定的vcl文件
200 0
八、varnish變量
客戶端發送過來的到本地varnishi的請求及本地發往後端web的請求:
req.*
req.request:請求的方法
req.url:請求的url地址
req.proto:請求的協議版本
req.backend:指定響應請求的後端web服務器
req.backend.healthy:後端web服務器健康狀態檢查
req.http.header:自定義首部信息,header可以替換成自己需要的首部。
req.can_gzip:是否使用gzip編碼
req.restarts:統計請求重啓次數,避免死循環。
varnish自己向後端web服務器發送的請求之前:
bereq.*
bereq.request:請求類型
bereq.url:請求的URL
bereq.http.header
bereq.connect_timeout:等待後端服務器連接超時時間(秒)
bereq.first_byte_timeout:
varnishi從後端web服務器獲得響應,並未處理之前:
beresp.*
向後端web服務器取得數據後,本地varnish操作方法:
obj.*
obj.hits:表示緩存在varnishi中的數據被命中次數,0表示沒有命中過。
對客戶端應答及web服務器對本地varnishi的響應:
resp.*
實例一、
目的:
檢查客戶端請求是否被varnishi緩存命中的方法
方法:
自定義在/etc/varnishi/下創建vcl。並應用
[[email protected] ~]# vim /etc/varnish/hit.vcl
backend backendserver{
.host = "10.40.0.229";
.port = "80";
}
sub vcl_fetch{
if (req.request == "GET" && req.url ~"\.(html|jpeg|jpg)$"){
set beresp.ttl = 3600s;
}
}
sub vcl_deliver{
if (obj.hits > 0 ){
set resp.http.X_CACHE = "HIT";
} else {
set resp.http.X_CACHE = "MISS";
} return (deliver);
}
[[email protected] ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
200 199
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,2.6.32-573.el6.x86_64,x86_64,-sfile,-hcritbit
Type 'help' for command list.
Type 'quit' to close CLI session.
vcl.load hit /etc/varnish/hit.vcl 加載新建的vcl文件
200 13
VCL compiled.
vcl.use hit 應用新的vcl實例
200 0
vcl.list 查看當前使用的實例
200 45
available 2 boot
active 1 hit
實驗二、
目的:
指定所有已htm結尾的url路徑都不從緩存中查找而是到後臺去查找。
方法:
backend backendserver{
.host = "10.40.0.229";
.port = "80";
}
sub vcl_recv {
set req.http.X-forword-for = client.ip; 設置記錄客戶端地真實址,用於日誌記錄,需要在後端web服務器上的httpd.conf文件中修改“LogFormat”參數爲“%{X-forward-for}i”,但是client.ip在演示時不可用,需要進一步瞭解。
if (req.url ~ "\.html$"){
return (pass);
}
}
sub vcl_fetch{
if (req.request == "GET" && req.url ~"\.(html|jpeg|jpg)$"){
set beresp.ttl = 3600s;
}
}
sub vcl_deliver{
if (obj.hits > 0 ){
set resp.http.X_CACHE = "HIT";
} else {
set resp.http.X_CACHE = "MISS";
} return (deliver);
}
實驗三、
目的:
通過varnish實現網站動靜分離功能、需要變量req.backend進行指定。
[[email protected] ~]# vim /etc/varnish/hit.vcl
backend backendhttp{
.host = "10.40.0.229";
.port = "80";
}
backend backendphp{
.host = "10.40.0.228";
.port = "80";
}
sub vcl_recv {
if (req.url ~ "\.html$"){
return (pass);
}
if (req.url ~"\.html$"){
set req.backend = backendhttp;
}else {
set req.backend = backendphp;
}
}
sub vcl_fetch{
if (req.request == "GET" && req.url ~"\.(html|jpeg|jpg)$"){
set beresp.ttl = 3600s;
}
}
sub vcl_deliver{
if (obj.hits > 0 ){
set resp.http.X_CACHE = "HIT";
} else {
set resp.http.X_CACHE = "MISS";
} return (deliver);
}
~
實驗四
目的:
對後端web服務器進行健康狀態檢查。
方法:
參數:
.url :指定檢測的網頁地址。
.timeout:定義超時時間。
.request:明確指明請求的方法
.window:採集後端服務器數據的次數,默認8次
.initial:探測次數,默認3次
.interval:探測時間間隔,默認5秒
.threshold:採集成功次數,默認3次
通過probe進行定義,可以將probe直接定義在backend裏面,也可以先定義probe一個實例名,然後再在backend裏面進行調用。
a、
backend backendhttp{
.host = "10.40.0.229";
.port = "80”;
.probe = {
.url = ‘/test.jpg’;
.timeout = 0.3s;
.windows = 8;
.threshold = 3;
.initial = 3;
}
}
b、
probe healthcheck {
.url = ‘/test.jpg’;
.timeout = 0.3s;
.windows = 8;
.threshold = 3;
.initial = 3;
}
backend backendhttp{
.host = "10.40.0.229";
.port = "80”;
.probe = healthcheck;
}
實驗五
目的:varnish對後端web服務器進行負載均衡。
方法:首先通過backend進行聲明,然後通過director 進行引用(方式有2種)。
director使用的調度算法包括round-robin和random兩種
round-robin是輪詢算法
random是隨機從可用後端服務器上進行挑選,需要權重值調整優先級。
random在之後又衍生出了client和hash兩種算法,其中client使用client.identify作爲挑選條件,這樣就可以使相同的client因子訪問相同的後端web服務器,,默認是client.ip可以修改自定義標識符。而hash挑選方法是對同一個URL的請求發送到同一個後端主機,常用於多級緩存場景中。
可以通過fallback來定義備用服務器。
backend backendhttp{
.host = "10.40.0.229";
.port = "80";
}
backend backendphp{
.host = "10.40.0.228";
.port = "80";
}
director web1 round-robin{
# .retries = 2;
{
.backend = backendhttp;
# .weight = 1;
}
{
.backend = backendphp;
# .weight = 1;
}
}
sub vcl_recv {
if (req.url ~"\.html$"){
return(pass);
}
set req.backend = web1;
}
sub vcl_fetch{
if (req.request == "GET" && req.url ~"\.(html|jpeg|jpg)$"){
set beresp.ttl = 3600s;
}
}
sub vcl_deliver{
if (obj.hits > 0 ){
set resp.http.X_CACHE = "HIT";
} else {
set resp.http.X_CACHE = "MISS";
} return (deliver);
}
實驗六
目的:
清理varnish過期緩存,設置訪問控制列表acl。
方法:
實驗七
目的:
設置網頁防止盜鏈問題
方法:
檢查referer是否是可允許的,或者是否是“站內鏈接”。
實驗八
目的:
工具說明param.show和param.set。分別用來顯示和設置varnish參數。
方法:
param.show
200 2411
acceptor_sleep_decay 0.900000 []
acceptor_sleep_incr 0.001000 [s]
acceptor_sleep_max 0.050000 [s]
auto_restart on [bool]
ban_lurker_sleep 0.000000 [s]
between_bytes_timeout 60.000000 [s]
cache_vbe_conns off [bool]
cc_command "exec cc -fpic -shared -Wl,-x -o %o %s"
cli_buffer 8192 [bytes]
cli_timeout 10 [seconds]
clock_skew 10 [s]
connect_timeout 0.400000 [s]
critbit_cooloff 180.000000 [s]
default_grace 10 [seconds]
default_ttl 120 [seconds]
diag_bitmap 0x0 [bitmap]
err_ttl 0 [seconds]
esi_syntax 0 [bitmap]
expiry_sleep 1.000000 [seconds]
fetch_chunksize 128 [kilobytes]
first_byte_timeout 60.000000 [s]
group varnish (302)
http_headers 64 [header lines]
http_range_support off [bool]
listen_address :80
listen_depth 1024 [connections] 排隊隊列長度
log_hashstring off [bool]
log_local_address off [bool]
lru_interval 2 [seconds] 清理過期緩存時間間隔
max_esi_includes 5 [includes]
max_restarts 4 [restarts]
overflow_max 100 [%]
ping_interval 3 [seconds]
pipe_timeout 60 [seconds]
prefer_ipv6 off [bool]
purge_dups on [bool]
rush_exponent 3 [requests per request]
saintmode_threshold 10 [objects]
send_timeout 600 [seconds]
sess_timeout 5 [seconds]
sess_workspace 65536 [bytes]
session_linger 50 [ms]
session_max 100000 [sessions]
shm_reclen 255 [bytes]
shm_workspace 8192 [bytes]
syslog_cli_traffic on [bool]
thread_pool_add_delay 20 [milliseconds]
thread_pool_add_threshold 2 [requests]
thread_pool_fail_delay 200 [milliseconds]
thread_pool_max 1000 [threads]
thread_pool_min 1 [threads]
thread_pool_purge_delay 1000 [milliseconds]
thread_pool_stack unlimited [bytes]
thread_pool_timeout 120 [seconds]
thread_pools 2 [pools]
thread_stats_rate 10 [requests]
user varnish (302)
vcl_trace off [bool]
waiter default (epoll, poll)
查看幫助信息:param.show -l
查看varnish連接狀態信息:
[[email protected] ~]# varnishstat
1+08:40:28 node6.dtedu.com
Hitrate ratio: 1 1 1
Hitrate avg: 0.2576 0.2576 0.2576
58 0.00 0.00 Client connections accepted 客戶端連接個數
66 0.00 0.00 Client requests received 客戶端請求個數
17 0.00 0.00 Cache hits 命中個數
49 0.00 0.00 Cache misses 未命中個數
30 0.00 0.00 Backend conn. success 成功連接後端次數
19 0.00 0.00 Backend conn. failures 失敗次數
30 0.00 0.00 Fetch with Length
11 . . N struct sess_mem
1 . . N struct objecthead
2 . . N struct smf
2 . . N large free smf
2 . . N worker threads 當前活動線程個數
2 0.00 0.00 N worker threads created 啓動工作線程個數
69799 0.00 0.59 N worker threads limited
1 . . N backends
30 . . N expired objects 過期對象個數
4 . . N LRU moved objects 移除的緩存對象的次數
55 0.00 0.00 Objects sent with write
58 0.00 0.00 Total Sessions
66 0.00 0.00 Total Requests
30 0.00 0.00 Total fetch
17423 0.00 0.15 Total header bytes
8465 0.00 0.07 Total body bytes
54 0.00 0.00 Session Closed
20 0.00 0.00 Session Linger
14 0.00 0.00 Session herd
11964 0.00 0.10 SHM records 共享內存記錄個數
8983 0.00 0.08 SHM writes
60 0.00 0.00 allocator requests
1073741824 . . bytes free
19 0.00 0.00 SMS allocator requests
7961 . . SMS bytes allocated
7961 . . SMS bytes freed
30 0.00 0.00 Backend requests made
1 0.00 0.00 N vcl total
1 0.00 0.00 N vcl available
1 . . N total active purges
1 0.00 0.00 N new purges added
66 0.00 0.00 HCB Lookups without lock
49 0.00 0.00 HCB Lookups with lock
49 0.00 0.00 HCB Inserts
117628 1.00 1.00 Client uptime
啓動和查看varnish日誌信息
[[email protected] ~]# service varnishlog start
Starting varnish logging daemon: [ OK ]
[[email protected] ~]# varnishlog
0 CLI - Rd ping
0 CLI - Wr 200 19 PONG 1503646793 1.0
0 CLI - Rd ping
0 CLI - Wr 200 19 PONG 1503646796 1.0
0 CLI - Rd ping
0 CLI - Wr 200 19 PONG 1503646799 1.0
CDN實現條件就是知道ip地址的歸屬,如何收集ip地址的歸屬,可以通過IANA來查詢