实现负载均衡

varnish所支持的调度方式有以下几种:

1.round-robin        #加权轮询,因为每个backend都有它的权重

2.random             #随机

3.dns                #基于DNS名称解析之后进行调度

 

例:

定义多个backend

directorNAME  scheduler {
     .retries = 2;
     {
          .backend = b1;
          .weight = 2;
     }

 

    .backend = b2;
     {
          .backend = {
              .host = 
              .port =
              .probe = 
          }
          .weight = 3;
     }
}

其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,挑选方式为“轮叫”,并在某后端主机故障时不再将其视作挑选对象;random方法随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数以指定其权重,同时还可以director级别使用.retires参数来设定查找一个健康后端主机时的尝试次数。

 

Varnish 2.1.0后,random挑选方法又多了两种变化形式client和hashclient类型的director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机,client.identity默认改为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。

类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。(类似于haproxy的URI算法)

 

另外还有一种称作fallback的director,用于定义备用服务器,如下所示:

 

director b3fallback {
  { .backend = www1; }
  { .backend = www2; } // will only be used if www1 is unhealthy.
  { .backend = www3; } // will only be used if both www1 and www2
                      // are unhealthy.

}

作用为多级备选,如果www1在线,其他不在线了,那么所有请求都转发至www1

如果www1也不在线了直接转向www2 以此类推,所以跟负载均衡是两码事,仅是其中一个,只有其中一个不在线则使用第二个,由此我们期望之前的几台服务器被当做一组服务器来使用

而且使用随机或者轮询的方法来实现

 

编辑配置文件

[[email protected]]# cat test.vcl

#设置缓存机制规则

probe healtchk {
   .url = "/";
   .interval = 1s;
   .timeout = 0.1s;
   .expected_response = 200;
}

 

backendimg_server1 {

        .host="10.0.10.63";

        .port="8080";

        .probe = healtchk;

}

 

backendapp_server1 {

        .host="10.0.10.62";

        .port="8080";

        .probe = healtchk;

}

#使用hash调度算法,将同一来源请求都分发至同一后端服务器

directorwebservers hash{

    {

     .backend = img_server1;

     .weight = 2;

    }

 

    {

     .backend = app_server1;

     .weight = 1;

    }

}

 

#定义需要缓存内容文件

 

sub vcl_recv {

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

    if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {

      return(pass);

}

 

#调用backend结果

    set req.backend = webservers;

}

 

 

sub vcl_deliver {

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

   if (obj.hits > 0) {

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

        } else {

               set resp.http.XCahche ="MISS";

        }

}

访问测试

                             Varnish常用配置详解

 

实现varnish自动清理缓存

有两种方式可以实现自动清理缓存:

·使用pruge

    修剪缓存,能够让用户清理所指定的某个特定缓存对象,如果要移除多个缓存对象,对缓存某些内容基于正则方式进行清理的话,可以进行banning这种机制

·Banning 

    通常可以移除指定的缓存对象或者进行匹配某些对象进行处理

 

想要使用purge,必须使用http协议的的purge方法即可完成,但是要注意的是其仅能用于vcl.hit和vcl.miss中,并且会释放内存而且移除缓存对象的所有变种,只要与缓存对象相关,都会被清除

如果能手动对象,而缓存的性能主要取决于缓存对象的,所以不能随意清理,因此如下所示:

#定义了acl,注意的是引号内不能有掩码位

 

示例

#定义了acl,注意的是引号内不能有掩码位

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);
        }
}

#对用户请求的操作进行purge操作
#并且执行错误码,结果是200,意味着是正常响应并告知请求方被执行

#但是用户purge一个对象,但是这个对象在缓存中压根没有,那么就没必要去清理,所以定义了miss

sub vcl_hit {
        if (req.request ==
“PURGE”) {
               purge;
               error 200 “Purged”;
        }
}

#如果是miss的话,直接返回404,但是purge操作会正常进行

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”;
        }
}

大致意思为:

如果用户的请求方法是purge 而且来源地址是属于允许执行purge的客户端那么则允许查询缓存

而刚好命中则删除;如果没有则告诉用户 404

 

修改参数如下所示:

[[email protected] varnish]# cattest.vcl

acl purgers {

    "127.0.0.1";

    "10.0.10.0"/24;

}

 

probe healtchk {

   .url = "/";

   .interval = 1s;

   .timeout = 0.1s;

   .expected_response = 200;

}

 

backend img_server1 {

  .host = "10.0.10.63";

  .port = "8080";

  .probe = healtchk;

}

 

backend app_server1 {

  .host = "10.0.10.62";

  .port = "8080";

  .probe = healtchk;

}

 

director webservers random {

    {

     .backend = img_server1;

     .weight = 2;

    }

 

    {

     .backend = app_server1;

     .weight = 1;

    }

}

 

sub vcl_recv {

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

                if (!client.ip ~ purgers) {

                        error 405 "Methodnot allowed";

                }

                return (lookup);

        }

 

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

 

   if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {

    return(lookup);

     }

 

    set req.backend = webservers;

}

 

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 passedoject.";

     }

}

 

sub vcl_deliver {

   if(obj.hits > 0) {

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

     } else {

            set resp.http.XCahche ="MISS";

     }

}

 

varnish> vcl.load test8./test.vcl

200       

VCL compiled.

varnish> vcl.use test8

200

 

访问测试,并观察其返回头部信息

首先清除缓存信息

[[email protected] html]# curl -XPURGE http://10.0.10.61/1.html

 

<?xmlversion="1.0" encoding="utf-8"?>

<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"

 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>

  <head>

   <title>200 Purged.</title>

  </head>

  <body>

    <h1>Error 200 Purged.</h1>

    <p>Purged.</p>

    <h3>Guru Meditation:</h3>

    <p>XID: 1620937044</p>

    <hr>

    <p>Varnish cache server</p>

  </body>

</html>

再次请求

[[email protected] html]# curl -IPURGE http://10.0.10.61/1.html

curl: (6) Couldn't resolvehost 'PURGE'

HTTP/1.1 200 OK

Server: nginx/1.4.2

Content-Type: text/html

Last-Modified: Fri, 18 Jul2014 06:50:23 GMT

ETag: "53c8c3af-4"

Content-Length: 4

Accept-Ranges: bytes

Date: Fri, 25 Jul 201407:27:23 GMT

X-Varnish: 1620937045

Age: 0

Via: 1.1 varnish

Connection: keep-alive

XCahche: MISS

再次测试

[[email protected] html]# curl -IPURGE http://10.0.10.61/1.html

curl: (6) Couldn't resolvehost 'PURGE'

HTTP/1.1 200 OK

Server: nginx/1.4.2

Content-Type: text/html

Last-Modified: Fri, 18 Jul2014 06:50:23 GMT

ETag: "53c8c3af-4"

Content-Length: 4

Accept-Ranges: bytes

Date: Fri, 25 Jul 201407:28:29 GMT

X-Varnish: 16209370471620937045

Age: 66

Via: 1.1 varnish

Connection: keep-alive

X-Cache: HIT from 10.0.10.61

发起对某一url的请求,第一次请求一定是MISS而之后都是命中的

-X表示将缓存清除,缓存清理之后再次请求则为miss

 

 

Varnish防盗链的设置

对其使用referer变量来标注用户的来源的首部信息

一般来讲,我们的连接都应该是我们自己本身的站内连接,或者其他子站连接

因此要阻止他人盗链我们站点连接,只能判断连接来源,请求首部信息的referer是否我们允许的连接

 

还是需要使用if语句判断用户的连接来源是处于哪里,而后对连接本身做一些访问控制,如下所示:

例:

如果匹配http协议,就对其做判断

如果请求方的referer如果不是这个站点,则拒绝

#还需要对搜索引擎网站开放,因为搜索引擎会收录我们的站点,从而去搜索某个关键字的时候从而可以将我们的某些站点搜索出来,这样可以提高我们的点击率,所以要允许搜索引擎访问我们的站点,不然搜索引擎无法收录我们的站点

if (req.http.referer ~"http://.*"){

  if(!(req.http.referer ~ "http://.*\.test\.com" ||req.http.referer ~ "http://.*\.baidu\.com\.*" )) {

     setreq.http.host = "www.test.com";                #将用户请求的主机名称改为自定义名

     setreq.url = "/antireferer/logo.html";            #并且直接返回我们本地资源的自定义url

         }

}

只要来源不是引用以上两个站点的,则返回logo.jpg盗链图片连接

修改配置文件:

将以上参数加入至RECV中

[[email protected] varnish]# cat test.vcl

acl purgers {

    "127.0.0.1";

    "10.0.10.0"/24;

}

 

probe healtchk {

   .url = "/";

   .interval = 1s;

   .timeout = 0.1s;

   .expected_response = 200;

}

 

backend img_server1 {

  .host = "10.0.10.63";

  .port = "8080";

  .probe = healtchk;

}

 

backend app_server1 {

  .host = "10.0.10.62";

  .port = "8080";

  .probe = healtchk;

}

 

director webservers random {

    {

     .backend = img_server1;

     .weight = 2;

    }

 

    {

     .backend = app_server1;

     .weight = 1;

    }

}

 

sub vcl_recv {

#加入以下参数

     if (req.http.referer ~ "http://.*"){

         if(!(req.http.referer ~ "http://.*\.test\.com" ||req.http.referer ~ "http://.*\.baidu\.com\.*" )) {

            set req.http.host = "www.test.com";     

            set req.url = "/antireferer/logo.jpg";   

         }

     }

 

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

            if (!client.ip ~ purgers) {

               error 405 "Method notallowed";

            }

               return (lookup);

     }

 

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

 

     if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {

     return(lookup);

     }

 

    set req.backend = webservers;

}

 

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 passedoject.";

     }

}

 

sub vcl_deliver {

   if(obj.hits > 0) {

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

     } else {

            set resp.http.XCahche ="MISS";

     }

}

 

 

[[email protected] varnish]# !ca

cat test.vcl

acl purgers {

    "127.0.0.1";

    "10.0.10.0"/24;

}

 

probe healtchk {

   .url = "/";

   .interval = 1s;

   .timeout = 0.1s;

   .expected_response = 200;

}

 

backend img_server1 {

  .host = "10.0.10.63";

  .port = "8080";

  .probe = healtchk;

}

 

backend app_server1 {

  .host = "10.0.10.62";

  .port = "8080";

  .probe = healtchk;

}

 

director webservers random {

    {

     .backend = img_server1;

     .weight = 2;

    }

 

    {

     .backend = app_server1;

     .weight = 1;

    }

}

 

sub vcl_recv {

      if (req.http.referer ~"http://.*"){

          if(!(req.http.referer ~"http://.*\.test\.com" || req.http.referer ~"http://.*\.baidu\.com\.*" )) {

             set req.http.host ="www.test.com";     

             set req.url ="/antireferer/logo.jpg";   

          }

     }

 

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

            if (!client.ip ~ purgers) {

               error 405 "Method notallowed";

            }

               return (lookup);

     }

 

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

 

     if(req.url ~"\.(html|jsp|css|gif|jpg|gif|jpeg)$") {

     return(lookup);

     }

 

    set req.backend = webservers;

}

 

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 passedoject.";

     }

}

 

sub vcl_deliver {

   if(obj.hits > 0) {

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

     } else {

            set resp.http.XCahche ="MISS";

     }

}

 

varnish> vcl.load test10./test.vcl

200       

VCL compiled.

varnish> vcl.use test10

200        

 

建立antireferer目录

[[email protected] www]# mkdirantireferer
[[email protected] antireferer]# pwd

/var/www/html/antireferer

#上传图片

[[email protected] antireferer]# rz

[[email protected] antireferer]# ll

total 44

-rw-r--r--. 1 root root 42142May 22  2011 log.jpg

 

验证效果

[[email protected] antireferer]#curl  -e http://www.baidu.com/a.htmlhttp://10.0.10.61/index.html

node1

11

[[email protected] antireferer]#curl  -e http://www.qq.com/a.htmlhttp://10.0.10.61/index.html

<html>

<head><title>404Not Found</title></head>

<bodybgcolor="white">

<center><h1>404 NotFound</h1></center>

<hr><center>nginx/1.4.2</center>

</body>

</html>

可以看到效果,我们以baidu.com为首部对其进行请求,可访问,但如果是从qq.com对其进行资源访问则返回错误

但是为啥返回404还在研究

 

 

vcl配置基本原则

自定义vcl的时候,尽量不要拿空白文件直接写,而要复制默认配置文件,将默认配置文件的参数全部启用,再在其基础做修改,因为默认配置文件的规则比较严谨,在安全防范上有一定效果的,自己写的难免会有漏洞

所以应该以default.vcl为模板,启用其所有配置后,再进行修改

 

 

END,感谢各位。