Varnish緩存服務器實現網站負載均衡、動靜分離

       varnish 緩存是 web 應用加速器,同時也做爲 http 反向緩存代理。你能夠安裝 varnish 在任何http 的前端,同時配置它緩存內容。與傳統的 squid 相比,varnish 具備性能更高、速度更快、管理更加方便等諸多優勢。php



案例1  使用Varnish實現負載均衡以及頁面緩存css


1 、拓撲環境html

Varnish:192.168.31.250前端

Web01:192.168.31.10nginx

Web02:192.168.31.20web

楊書凡06.png



二、安裝 varnish、web0一、web02
算法

[root@varnish ~]#  yum -y install  varnish後端

[root@web01 ~]#  yum -y install nginx緩存

[root@web02 ~]#  yum -y install nginx安全


三、varnish 的vcl  文件配置內容:

[root@varnish ~]#  cat  /etc/varnish/default.vcl

#使用 varnish 版本 4 的格式.
vcl 4.0;
#加載後端負載均衡模塊
import directors;
#加載 std 模塊
import std;
#建立名爲 backend_healthcheck 的健康檢查策略
probe backend_healthcheck {
.url="/";
.interval = 5s;
.timeout = 1s;
.window = 5;
.threshold = 3;
}
#定義後端服務器
backend web_app_01 {
.host = "192.168.31.10";
.port = "80";
.first_byte_timeout = 9s;
.connect_timeout = 3s;
.between_bytes_timeout = 1s;
.probe = backend_healthcheck;
}
backend web_app_02 {
.host = "192.168.31.20";
.port = "80";
.first_byte_timeout = 9s;
.connect_timeout = 3s;
.between_bytes_timeout = 1s;
.probe = backend_healthcheck;
}
#定義容許清理緩存的 IP
acl purgers {
"127.0.0.1";
"localhost";
"192.168.31.0/24";
}
#vcl_init 初始化子程序建立後端主機組
sub vcl_init {
new web = directors.round_robin();
web.add_backend(web_app_01);
web.add_backend(web_app_02);
}
#請求入口,用於接收和處理請求。這裏通常用做路由處理,判斷是否讀取緩存和指定該請求使用哪一個後端
sub vcl_recv {
        #將請求指定使用 web 後端集羣 .在集羣名後加上 .backend()
set req.backend_hint = web.backend();
# 匹配清理緩存的請求
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return (synth(405, "Not Allowed."));
}
# 是的話就執行清理
return (purge);
}
# 若是不是正常請求 就直接穿透沒商量
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 就跳到 pass
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
#若是匹配動態內容訪問請求就跳到 pass
if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {
return (pass);
}
#具備身份驗證的請求跳到 pass
if (req.http.Authorization) {
return (pass);
}
if (req.http.Accept-Encoding) {
if  (req.url  ~
"\.(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$") {
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;
}
}
if  (req.url  ~
"\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)
($|\?)") {
unset req.http.cookie;
return (hash);
}
# 把真實客戶端 IP 傳遞給後端服務器 後端服務器日誌使用 X-Forwarded-For 來接收
if (req.restarts == 0) {
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
return (hash);
}
# hash 事件(緩存事件)
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (lookup);
}
# 緩存命中事件
sub vcl_hit {
if (req.method == "PURGE") {
return (synth(200, "Purged."));
}
return (deliver);
}
# 緩存不命中事件
sub vcl_miss {
if (req.method == "PURGE") {
return (synth(404, "Purged."));
}
return (fetch);
}
# 返回給用戶的前一個事件 一般用於添加或刪除 header 頭
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
set resp.http.X-Cache-Hits = obj.hits;
} else {
set resp.http.X-Cache = "MISS";
}
#取消顯示 php 框架版本的 header 頭
unset resp.http.X-Powered-By;
#取消顯示 web 軟件版本、Via(來自 varnish)等 header 頭 爲了安全
unset resp.http.Server;
unset resp.http.X-Drupal-Cache;
unset resp.http.Via;
unset resp.http.Link;
unset resp.http.X-Varnish;
#顯示請求經歷 restarts 事件的次數
set resp.http.xx_restarts_count = req.restarts;
#顯示該資源緩存的時間單位秒
set resp.http.xx_Age = resp.http.Age;
#顯示該資源命中的次數
set resp.http.hit_count = obj.hits;
#取消顯示 Age 爲了避免和 CDN 衝突
unset resp.http.Age;
#返回給用戶
return (deliver);
}
# pass 事件
sub vcl_pass {
return (fetch);
}
#處理對後端返回結果的事件(設置緩存、移除 cookie 信息、設置 header 頭等) 在 fetch 事件後自動調用
sub vcl_backend_response {
#開啓 grace 模式 表示當後端全掛掉後 即便緩存資源已過時(超過緩存時間) 也會把該資源返回給用戶 資源最大有效時間爲 5 分鐘
set beresp.grace = 5m;
#後端返回以下錯誤狀態碼 則不緩存
if (beresp.status == 499 || beresp.status == 404 || beresp.status == 502) {
set beresp.uncacheable = true;
}
#如請求 php 或 jsp 則不緩存
if (bereq.url ~ "\.(php|jsp)(\?|$)") {
set beresp.uncacheable = true;
} else { //自定義緩存文件的緩存時長,即 TTL 值
if (bereq.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico)($|\?)") {
set beresp.ttl = 15m;
unset beresp.http.Set-Cookie;
} elseif (bereq.url ~ "\.(gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {
set beresp.ttl = 30m;
unset beresp.http.Set-Cookie;
} else {
set beresp.ttl = 10m;
unset beresp.http.Set-Cookie;
}
}
#返回給用戶
return (deliver);
}
sub vcl_purge {
return (synth(200,"success"));
}
sub vcl_backend_error {
if (beresp.status == 500 ||
beresp.status == 501 ||
beresp.status == 502 ||
beresp.status == 503 ||
beresp.status == 504) {
return (retry);
}
}
sub vcl_fini {
return (ok);
}


四、啓動Varnish

[root@varnish ~]# varnishd  -f  /etc/varnish/default.vcl        #啓動

[root@varnish ~]# pkill  varnishd                                       #關閉服務


五、客戶端訪問驗證

訪問varnish服務器 http://192.168.31.250,varnish會根據算法分配流量




案例2  使用Varnish實現動靜分離

1 、拓撲環境

Varnish:192.168.31.250

Web01:192.168.31.10

Web02:192.168.31.20

注意:在實現兩臺後端主機負載均衡時需將此路徑設置爲不緩存直接從後端主機中取得數據



varnish 的vcl  文件配置內容:

[root@varnish ~]#  cat  /etc/varnish/default.vcl

#使用 varnish 版本 4 的格式.

vcl 4.0;

#加載後端負載均衡模塊

import directors;

#加載 std 模塊

import std;

#建立名爲 backend_healthcheck 的健康檢查策略

probe backend_healthcheck {

.url="/";

.interval = 5s;

.timeout = 1s;

.window = 5;

.threshold = 3;

}

#定義後端服務器

backend web_app_01 {

.host = "192.168.31.10";

.port = "80";

.first_byte_timeout = 9s;

.connect_timeout = 3s;

.between_bytes_timeout = 1s;

.probe = backend_healthcheck;

}

backend web_app_02 {

.host = "192.168.31.20";

.port = "80";

.first_byte_timeout = 9s;

.connect_timeout = 3s;

.between_bytes_timeout = 1s;

.probe = backend_healthcheck;

}

#定義容許清理緩存的 IP

acl purgers {

"127.0.0.1";

"localhost";

"192.168.31.0/24";

}

#vcl_init 初始化子程序建立後端主機組

sub vcl_init {

new web = directors.round_robin();

web.add_backend(web_app_01);

web.add_backend(web_app_02);

}

#請求入口,用於接收和處理請求。這裏通常用做路由處理,判斷是否讀取緩存和指定該請求使用哪一個後端

sub vcl_recv {

        #將.php結尾的文件發往web_app_01,將其餘結尾的文件發往web_app_02

        if (req.url ~ "(?i)\.php$") {           

            set req.backend_hint = web_app_01; 

            } else { 

            set req.backend_hint = web_app_02;          

            }    

        #url中開頭帶有login的直接從後端主機取結果不緩存 

        if (req.url ~"(?i)^/login") {          

        return(pass); 

        }

# 匹配清理緩存的請求

if (req.method == "PURGE") {

if (!client.ip ~ purgers) {

return (synth(405, "Not Allowed."));

}

# 是的話就執行清理

return (purge);

}

# 若是不是正常請求 就直接穿透沒商量

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 就跳到 pass

if (req.method != "GET" && req.method != "HEAD") {

return (pass);

}

#若是匹配動態內容訪問請求就跳到 pass

if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") {

return (pass);

}

#具備身份驗證的請求跳到 pass

if (req.http.Authorization) {

return (pass);

}

if (req.http.Accept-Encoding) {

if  (req.url  ~

"\.(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$") {

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;

}

}

if  (req.url  ~

"\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)

($|\?)") {

unset req.http.cookie;

return (hash);

}

# 把真實客戶端 IP 傳遞給後端服務器 後端服務器日誌使用 X-Forwarded-For 來接收

if (req.restarts == 0) {

if (req.http.X-Forwarded-For) {

set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;

} else {

set req.http.X-Forwarded-For = client.ip;

}

}

return (hash);

}

# hash 事件(緩存事件)

sub vcl_hash {

hash_data(req.url);

if (req.http.host) {

hash_data(req.http.host);

} else {

hash_data(server.ip);

}

return (lookup);

}

# 緩存命中事件

sub vcl_hit {

if (req.method == "PURGE") {

return (synth(200, "Purged."));

}

return (deliver);

}

# 緩存不命中事件

sub vcl_miss {

if (req.method == "PURGE") {

return (synth(404, "Purged."));

}

return (fetch);

}

# 返回給用戶的前一個事件 一般用於添加或刪除 header 頭

sub vcl_deliver {

if (obj.hits > 0) {

set resp.http.X-Cache = "HIT";

set resp.http.X-Cache-Hits = obj.hits;

} else {

set resp.http.X-Cache = "MISS";

}

#取消顯示 php 框架版本的 header 頭

unset resp.http.X-Powered-By;

#取消顯示 web 軟件版本、Via(來自 varnish)等 header 頭 爲了安全

unset resp.http.Server;

unset resp.http.X-Drupal-Cache;

unset resp.http.Via;

unset resp.http.Link;

unset resp.http.X-Varnish;

#顯示請求經歷 restarts 事件的次數

set resp.http.xx_restarts_count = req.restarts;

#顯示該資源緩存的時間單位秒

set resp.http.xx_Age = resp.http.Age;

#顯示該資源命中的次數

set resp.http.hit_count = obj.hits;

#取消顯示 Age 爲了避免和 CDN 衝突

unset resp.http.Age;

#返回給用戶

return (deliver);

}

# pass 事件

sub vcl_pass {

return (fetch);

}

#處理對後端返回結果的事件(設置緩存、移除 cookie 信息、設置 header 頭等) 在 fetch 事件後自動調用

sub vcl_backend_response {

#開啓 grace 模式 表示當後端全掛掉後 即便緩存資源已過時(超過緩存時間) 也會把該資源返回給用戶 資源最大有效時間爲 5 分鐘

set beresp.grace = 5m;

#後端返回以下錯誤狀態碼 則不緩存

if (beresp.status == 499 || beresp.status == 404 || beresp.status == 502) {

set beresp.uncacheable = true;

}

#如請求 php 或 jsp 則不緩存

if (bereq.url ~ "\.(php|jsp)(\?|$)") {

set beresp.uncacheable = true;

} else { //自定義緩存文件的緩存時長,即 TTL 值

if (bereq.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico)($|\?)") {

set beresp.ttl = 15m;

unset beresp.http.Set-Cookie;

} elseif (bereq.url ~ "\.(gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") {

set beresp.ttl = 30m;

unset beresp.http.Set-Cookie;

} else {

set beresp.ttl = 10m;

unset beresp.http.Set-Cookie;

}

}

#返回給用戶

return (deliver);

}

sub vcl_purge {

return (synth(200,"success"));

}

sub vcl_backend_error {

if (beresp.status == 500 ||

beresp.status == 501 ||

beresp.status == 502 ||

beresp.status == 503 ||

beresp.status == 504) {

return (retry);

}

}

sub vcl_fini {

return (ok);

}

相關文章
相關標籤/搜索