缓存服务器Varnish实践篇(2)

[root@localhost ~]# vim /etc/varnish/test.vcl

//添加如下内容:

backend web1 {              //添加后端服务器web1,地址为172.16.8.5,端口为81,probe表示健康状态检测

.host = "172.16.8.5"; 

.port = "81";

.probe = {

.url = "/index.html";  //健康检查要检查的文件

.interval = 1s;    //每隔1秒对此后端主机172.16.8.5:81探测一次

.window = 3;      //最近3次的探测请求

.threshold = 1;    //在最近3次的探测请求中至少有1次是成功的(响应码为200)就判定此后端主机为正常工作状态。

}

}

backend web2 {          //定义后端服务器web2

.host = "172.16.8.5";

.port = "82";

.probe = {

.url = "/index.html";

.interval = 1s;

.window = 3;

.threshold = 1;

}

}

backend img1 {      //定义后端图片服务器img1

.host = "172.16.8.5";

.port = "83";

.probe = {

.url = "/car.jpg";

.interval = 1s;

.window = 3;

.threshold = 1;

}

}

backend img2 {      //定义后端图片服务器img2

.host = "172.16.8.5";

.port = "84";

.probe = {

.url = "/car.jpg";

.interval = 1s;

.window = 3;

.threshold = 1;

}

}

backend php1 {      //定义后端php服务器php1

.host = "172.16.8.5";

.port = "85";

.probe = {

.url = "/index.php";

.interval = 1s;

.window = 3;

.threshold = 1;

}

}

backend php2 {    //定义后端php服务器php2

.host = "172.16.8.5";

.port = "86";

.probe = {

.url = "/index.php";

.interval = 1s;

.window = 3;

.threshold = 1;

}

}

director webserver random {      //定义web集群,采用random调度

{ .backend = web1; .weight = 3; }

{ .backend = web2; .weight = 1; }

}

director imgserver random {      //定义img集群

{ .backend = img1; .weight = 3; }

{ .backend = img2; .weight = 1; }

}

director phpserver random {    //定义php集群

{ .backend = php1; .weight = 3; }

{ .backend = php2; .weight = 1; }

}

sub vcl_recv {       

if (req.request == "PURGE") {  //定义缓存修剪

if (!client.ip ~ purgers) {

error 405 "Method not allowed";

}

return (lookup);

}

if (req.url ~ "\.php$"){    //如果请求是以.php结尾的,则pass,不缓存,直接交给后端处理响应

set req.backend = phpserver;

return(pass);

}

if (req.url ~ "\.(html|css|js)$"){ //如果是以.html .css .js 结尾的则发往web集群

set req.backend = webserver;

}

if (req.url ~ "\.(jpg|jpeg|png|gif)$"){  //如果是以.jpg .jpeg .png .gif 结尾的则发往img集群

set req.backend = imgserver;

}

}

sub vcl_fetch {        //根据响应的内容做出缓存决策

if (req.request == "GET" && req.url ~ "\.(html|css|js|jpg|jpeg|png|gif)$") {

set beresp.ttl = 3600s;    //缓存3600s

}

}

acl purgers {    //可以修剪缓存的用户地址

"127.0.0.1";

"172.16.8.2";

}

sub vcl_hit {    //如果请求的缓存存在,则执行purge命令,清除缓存

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

purge;

error 200 "Purged";  //返还200的error状态吗

}

}

sub vcl_miss {  //如果请求的内容缓存不存在,则返还404错误

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

purge;                     

error 404 "Not in cache";

}

}

sub vcl_pass {

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

error 502 "PURGE on a passed object";

}

}

sub vcl_deliver {    //修改vcl_deliver增一个响应头部

if (obj.hits > 0) {

set resp.http.X-Cache = "HIT from"+" "+server.ip;

}

else {

set resp.http.X-Cache = "Miss via"+" "+server.ip;

}

}

简单说明下此vcl文件:

在此vcl文件中采用了健康状态检查,缓存修剪,集群等功能

1、Varnish 检测后端主机的健康状态

Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判,Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。

.probe中的探测指令常用的有:
(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;
(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;

(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测进行,默认是8;
(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机正健康运行;默认是3;
(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;
(6) .expected_response:期望后端主机响应的状态码,默认为200;
(7) .interval:探测请求的发送周期,默认为5秒;
(8) .timeout:每次探测请求的过期时长,默认为2秒;

因此,如上vcl文件web1中表示每隔1秒对此后端主机探测一次,请求的URL为:81/index.html,在最近3次的探测请求中至少有1次是成功的(响应码为200)就判定此后端主机为正常工作状态。

2、Varnish 缓存修剪

1、缓存内容修剪

提高缓存命中率的最有效途径之一是增加缓存对象的生存时间(TTL),但是这也可能会带来副作用,比如缓存的内容在到达为其指定的有效期之间已经失效。因此,手动检验缓存对象的有效性或者刷新缓存是缓存很有可能成为服务器管理员的日常工作之一,相应地,Varnish为完成这类的任务提供了三种途径:HTTP 修剪(HTTP purging)、禁用某类缓存对象(banning)和强制缓存未命令(forced cache misses)。

这里需要特殊说明的是,Varnish 2中的purge()操作在Varnish 3中被替换为了ban()操作,而Varnish 3也使用了purge操作,但为其赋予了新的功能,且只能用于vcl_hit或vcl_miss中替换Varnish 2中常用的set obj.ttl=0s。

在具体执行某清理工作时,需要事先确定如下问题:
(1)仅需要检验一个特定的缓存对象,还是多个?
(2)目的是释放内存空间,还是仅替换缓存的内容?
(3)是不是需要很长时间才能完成内容替换?
(4)这类操作是个日常工作,还是仅此一次的特殊需求?

2、移除单个缓存对象

purge用于清理缓存中的某特定对象及其变种(variants),因此,在有着明确要修剪的缓存对象时可以使用此种方式。HTTP协议的PURGE方法可以实现purge功能,不过,其仅能用于vcl_hit和vcl_miss中,它会释放内存工作并移除指定缓存对象的所有Vary:-变种,并等待下一个针对此内容的客户端请求到达时刷新此内容。另外,其一般要与return(restart)一起使用。

3、强制缓存未命中

在vcl_recv中使用return(pass)能够强制到上游服务器取得请求的内容,但这也会导致无法将其缓存。使用purge会移除旧的缓存对象,但如果上游服务器宕机而无法取得新版本的内容时,此内容将无法再响应给客户端。使用req.has_always_miss=ture,可以让Varnish在缓存中搜寻相应的内容但却总是回应“未命中”,于是vcl_miss将后续地负责启动vcl_fetch从上游服务器取得新内容,并以新内容缓存覆盖旧内容。此时,如果上游服务器宕机或未响应,旧的内容将保持原状,并能够继续服务于那些未使用req.has_always_miss=true的客户端,直到其过期失效或由其它方法移除。

4、Banning

ban()是一种从已缓存对象中过滤(filter)出某此特定的对象并将其移除的缓存内容刷新机制,不过,它并不阻止新的内容进入缓存或响应于请求。在Varnish中,ban的实现是指将一个ban添加至ban列表(ban-list)中,这可以通过命令行接口或VCL实现,它们的使用语法是相同的。ban本身就是一个或多个VCL风格的语句,它会在Varnish从缓存哈希(cache hash)中查找某缓存对象时对搜寻的对象进行比较测试,因此,一个ban语句就是类似匹配所有“以/downloads开头的URL”,或“响应首部中包含nginx的对象”。例如:

ban req.http.host == "test.com"&& req.url ~ "\.gif$"

定义好的所有ban语句会生成一个ban列表(ban-list),新添加的ban语句会被放置在列表的首部。缓存中的所有对象在响应给客户端之前都会被ban列表检查至少一次,检查完成后将会为每个缓存创建一个指向与其匹配的ban语句的指针。Varnish在从缓存中获取对象时,总是会检查此缓存对象的指针是否指向了ban列表的首部。如果没有指向ban列表的首部,其将对使用所有的新添加的ban语句对此缓存对象进行测试,如果没有任何ban语句能够匹配,则更新ban列表。

我们这里采用的第2种方法来修剪缓存,只能通过172.16.8.2,和127.0.0.1这2个地址来删除缓存!

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/58246c0fc4fbc3f6a3f98e30cb5cdb5c.html