os:
php
[root@aliyun_test html]# cat /etc/system-releasehtml
CentOS release 6.5 (Final)java
首先安裝varnish:
linux
配置好varnish源nginx
[root@aliyun_test yum.repos.d]# cat >> varnish.repo << EOFweb
> [varnish]算法
> name=varnish for enterprise linux 6vim
> baseurl=https://repo.varnish-cache.org/redhat/varnish-4.0/el6/後端
> enabled=1瀏覽器
> gpgcheck=0
> cost=500
> EOF
安裝varnish
yum -y install varnish
[root@aliyun_test html]# varnishd -V
varnishd (varnish-4.0.3 revision b8c4a34)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2014 Varnish Software AS
Varnish 處理 HTTP 請求的過程以下
Receive 狀態(vcl_recv):也就是請求處理的入口狀態,根據 VCL 規則判斷該請求應該 pass(vcl_pass)或是 pipe(vcl_pipe),仍是進入 lookup(本地查詢);
Lookup 狀態:進入該狀態後,會在 hash 表中查找數據,若找到,則進入 hit(vcl_hit)狀態,不然進入 miss(vcl_miss)狀態;
Pass(vcl_pass)狀態:在此狀態下,會直接進入後端請求,即進入 fetch(vcl_fetch)狀態;
Fetch(vcl_backend_fetch)狀態:在 fetch 狀態下,對請求進行後端獲取,發送請求,得到數據,並根據設置進行本地存儲;
Deliver(vcl_deliver)狀態:將獲取到的數據發給客戶端,而後完成本次請求;
注:Varnish4中在vcl_fetch部分略有出入,已獨立爲vcl_backend_fetch和vcl_backend_response 2個函數;
內置函數(也叫子例程)
vcl_recv:用於接收和處理請求;當請求到達併成功接收後被調用,經過判斷請求的數據來決定如何處理請求;
vcl_pipe:此函數在進入pipe模式時被調用,用於將請求直接傳遞至後端主機,並將後端響應原樣返回客戶端;
vcl_pass:此函數在進入pass模式時被調用,用於將請求直接傳遞至後端主機,但後端主機的響應並不緩存直接返回客戶端;
vcl_hit:在執行 lookup 指令後,在緩存中找到請求的內容後將自動調用該函數;
vcl_miss:在執行 lookup 指令後,在緩存中沒有找到請求的內容時自動調用該方法,此函數可用於判斷是否須要從後端服務器獲取內容;
vcl_hash:在vcl_recv調用後爲請求建立一個hash值時,調用此函數;此hash值將做爲varnish中搜索緩存對象的key;
vcl_purge:pruge操做執行後調用此函數,可用於構建一個響應;
vcl_deliver:將在緩存中找到請求的內容發送給客戶端前調用此方法;
vcl_backend_fetch:向後端主機發送請求前,調用此函數,可修改發日後端的請求;
vcl_backend_response:得到後端主機的響應後,可調用此函數;
vcl_backend_error:當從後端主機獲取源文件失敗時,調用此函數;
vcl_init:VCL加載時調用此函數,常常用於初始化varnish模塊(VMODs)
vcl_fini:當全部請求都離開當前VCL,且當前VCL被棄用時,調用此函數,常常用於清理varnish模塊;
vcl_pass:請求後端,但不進入到cache中
client---------->varnish-------------->backend severs
client------>varnish:req請求報文
varnish----->backend:bereq向後端請求
backend----->varnish:beresp後端響應給緩存服務器
varnish----->client:resp緩存響應給client
緩存處理的具體步驟:
接受客戶端請求
解析請求(具備代理的功能)
查詢緩存(檢測本地緩存中是否存在對方請求的內容的副本)
副本的新鮮度檢測(檢查本地的緩存副本是否爲最新版本)
構建響應(代理的功能)
發送響應
記錄日誌
首部:
通用首部
Connection:close|keep-alive
Date:日期時間
host:請求的主機
Pragma:no-cache
Via:請求或響應在客戶端和服務器之間傳遞時所通過的代理
Transfer-Encoding:消息主體的傳輸編碼方式,chunked表示採用塊編碼的方式
請求首部
if-modified-since
if-none-match
Referer:跳轉
User-Agent:用戶的瀏覽器類型
Host:請求的主機
Accept-Encoding:接受的編碼方式
Accept-Language:接受的天然語言
Authorization:服務器發送www-authenticate時,客戶端經過此首部提供認證信息
Accept-Charset:接受的字符集
響應首部
ETag:內容的擴展標籤
Location:重定向後的新位置
Server:服務器軟件信息
www-authenticate:要求對客戶端進行認證
實體首部
Content-Encoding:內容編碼
Content-Language:內容語言
Content-Length:內容長度
Content-Type:內容的MIME格式
Expires:內容的過時時間
Last-Modified:最後一次修改的時間
配置文件:
vi /etc/sysconfig/varnish
NFILES=131072:打開的最大文件數
NFILES=131072:默認日誌內存大小
NPROCS="unlimited":最大線程數(ulimit -u)
RELOAD_VCL=1:直接加載,不用重啓
VARNISH_LISTEN_PORT=6081:varnish服務監聽的端口,通常改成與後端web服務同樣的端口
VARNISH_ADMIN_LISTEN_PORT=6082:遠程管理接口監聽的端口
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1:遠程管理端監聽的ip(本機varnish服務)
VARNISH_SECRET_FILE=/etc/varnish/secret:對管理接口祕鑰文件
VARNISH_MIN_THREADS=50:varnish服務開啓的最小線程
VARNISH_MAX_THREADS=1000:varnish服務開啓的最大線程
VARNISH_STORAGE_SIZE=256M:varnish服務存儲的內存大小
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}":varnish緩存存儲的方式,malloc內存
VARNISH_TTL=120
vi /etc/varnish/default.vcl
backend default {:後端web服務器以及名稱
.host = "127.0.0.1";:後端web服務器主機
.port = "8080";:後端web服務器監聽的端口
}
varnish存儲緩存內容的方法:
一、file:自管理的文件系統,黑盒,只對當前進程有效,不支持持久機制;
二、malloc:使用內存分配函數malloc()庫調用varnish啓動時向內存申請指定大小的空間;
三、persisent:與file功能相同;仍處於測試期,基於文件的持久存儲。
開始配置varnish並啓動:
後端服務器:120.26.68.152端口爲8080,爲nginx
varnish服務器:120.26.68.152端口爲7480
echo "<h1> test </h1>" > /usr/share/nginx/html/index.html
配置:vim /etc/varnish/test.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;
} ##判斷若是命中就在http響應首部設置X-Cache爲HIT,不然
就在http響應首部設置X-Cache爲MISS。
}
以下結果:
Age:表示緩存的時長(這裏設置一個小時),當超過這個時長以後,請求報文會再次miss,以後的1個小時纔是hit
sub vcl_backend_response {
set beresp.ttl = 1h;
}
vcl_backend_response:子程序爲後端響應給varnish
一些動態解析的程序文件都不可以緩存:
backend default { ----》先定義後端服務器
.host = "192.168.1.112";
.port = "80";
}
sub vcl_recv {
set req.backend_hint = default; ---》設置使用的backend爲default
unset req.http.Cookie; -----》不設置客戶端請求的cookie信息
if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)$") { ----》匹配的是默認後端主機
return(pass); ----》請求的是默認後端主機,若是不先設置主機將會網頁訪問不存在
}
}
設置默認後端效果圖:
若是不先設置默認主機,效果以下:
不正常的請求不緩存 -----》在vcl_rcv子程序中
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "PATCH" &&
req.method != "DELETE") {
return (pipe);
}
若是請求不是GET或者HEAD,不緩存
if (req.method != "GET" && req.method !="HEAD") {
return (pass);
}
若是請求包含Authorization受權或Cookie認證,不緩存
if (req.http.Authorization || req.http.Cookie) {
return (pass);
}
啓用壓縮,但排除一些流文件壓縮
if (req.http.Accept-Encoding) {
unset req.http.Accept-Encoding;
} elseif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elseif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
unset req.http.Accept-Encoding;
}
}
return (hash);
}
定義vcl_pipe函數段
sub vcl_pipe {
return (pipe);
}
sub vcl_miss {
return (fetch);
}
定義vcl_hash函數段
sub vcl_hash {
hash_data(req.url);
if (req.http.host) { -----》若是請求host首部,利用has算法返回host首部信息
hash_data(req.http.host);
}else {
hash_data(server.ip);
}
if (req.http.Accept-Encoding ~ "gzip") {
hash_data ("gzip");
}elseif (req.http.Accept-Encoding ~ "deflate") {
hash_data ("deflate");
}
}
sub vcl_recv {
if (req.restarts ==0) {:剛接收到請求,或者再一次請求時,記錄客戶端首部及ip
if (req.http.x-forwad-for) {
set req.http.X-Forward-For = set req.http.X-Forward-For + " " client.ip;
} else {
set req.http.X-Forward-For = client.ip;
}
}
}
這裏我已經改用虛擬機測試了
varnish:192.168.1.155
nginx:192.168.1.11
隱藏後端Server系統及版本
if (resp.http.Server) {
unset resp.http.Server;
}屬於sub vcl_deliver子程序
能夠看見響應報文沒有Server段了
定義兩個後端:
backend default {
.host = "192.168.1.11";
.port = "80";
}
backend java {
.host = "192.168.1.12";
.port = "80";
}
當匹配java時,選擇java後端,其餘默認選擇默認端
sub vcl_recv {
if (req.url ~ "^/java/") {
set req.backend_hint = java;-----》hint暗示、示意
} else {
set req.backend_hint = default;
}
}
根據請求報文的主機來判斷:
sub vcl_recv {
if (req.http.host ~ "foo.com") {
set req.backend_hint = foo;
} elsif (req.http.host ~ "bar.com") {
set req.backend_hint = bar;
}
}
sub vcl_recv {
if (req.http.host == "foo.com" || req.http.host == "www.foo.com") {
set req.backend_hint = foo;
}
}
定義後端組,而且採用round robin算法和後端服務器監控檢測機制
import directors; # load the directors
backend web1 {
.host = "192.168.1.11";
.port = "80";
.probe = {
.url = "/";
.interval = 5s;
.window = 5;
.timeout = 1s;
.threshold = 3;
}
}
backend web2 {
.host = "192.168.1.12";
.port = "80";
.probe = {
.url = "/";
.interval = 5s;
.timeout = 1s;
.window = 5;
.threshold = 3;
}
}
sub vcl_init {
new nginx = directors.round_robin(); -----》nginx就是後端組的組名稱,進行輪訓
nginx.add_backend(web1);
nginx.add_backend(web2);
}
sub vcl_recv {
# send all traffic to the bar director:
set req.backend_hint = nginx.backend();
}
ACL控制列表
# Who is allowed to purge....
acl local {
"localhost";
"192.168.1.0"/24; /* and everyone on the local network */
! "192.168.1.13"; /* except for the dialin router */
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip ~ local) {
return(purge);
} else {
return(synth(403, "Access denied."));
}
}
}
不設置請求報文的cookie信息
sub vcl_recv {
unset req.http.Cookie;
}
不設置響應報文的cookie信息
sub vcl_backend_response {
if (bereq.url ~ "\.(png|gif|jpg)$") {
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
}