首页 > 代码库 > varnish+nginx实现单双web服务器缓存

varnish+nginx实现单双web服务器缓存

实验目的:

varnish利用实现对后端单双静态web服务器的缓存

varnish包的下载路径:http://repo.varnish-cache.org/redhat/varnish-3.0/el6 可以下载到varnish的rpm包

需要下载的有:

varnish-3.0.5-1.el6.x86_64

varnish-docs-3.0.5-1.el6.x86_64

varnish-libs-3.0.5-1.el6.x86_64

varnish的官网地址:https://www.varnish-cache.org/

实验环境:

web1:172.16.18.3            Nginx

web2:172.16.17.12          Nginx

varnish:172.16.18.1         Varnish

实验内容:

一,安装varnish包,配置web服务器

[root@node1~]# rpm -ql varnish     
/etc/rc.d/init.d/varnish              #varnish的启动程序     
/etc/rc.d/init.d/varnishlog           #日志     
/etc/rc.d/init.d/varnishncsa          #日志     
/etc/sysconfig/varnish                #配置文件,varnish定义自身属性     
/etc/varnish                          #配置文件目录     
/etc/varnish/default.vcl              #默认配置文件,定义后端节点的     
/usr/bin/varnish_reload_vcl           #加载vcl,     
/usr/bin/varnishadm                   #客户端程序     
/usr/bin/varnishstat                  #状态监控

二,编辑配置文件

[root@node1 ~]# vim /etc/sysconfig/varnish
NFILES=131072
MEMLOCK=82000
NPROCS="unlimited"
RELOAD_VCL=1                                                        #是否重载VCL文件
## Alternative 3, Advanced configuration
VARNISH_VCL_CONF=/etc/varnish/default.vcl              #vcl文件路径
VARNISH_LISTEN_PORT=80                                     #varnish自己工作于那个端口。默认是6081
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1       #管理接口
VARNISH_ADMIN_LISTEN_PORT=6082                    #管理接口监听端口
VARNISH_SECRET_FILE=/etc/varnish/secret                #密钥文件
VARNISH_MIN_THREADS=50                                    #最少空闲线程
VARNISH_MAX_THREADS=1000                                #最多启动线程
VARNISH_THREAD_TIMEOUT=120                            #work超时时长
#VARNISH_STORAGE_FILE=/var/lib/varnish/varnish_storage.bin        #存储文件
VARNISH_STORAGE_SIZE=64M                                                    #存储文件文件大小
#VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"    #存储方式file
VARNISH_STORAGE="malloc,${VARNISH_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}"


[root@node1 ~]# vim /etc/varnish/default.vcl
backend default {
  .host = "172.16.18.3";
  .port = "80";
}

此时varnish就已经可以启动了。下来就是最重要的编写vcl文件。

那么我们就应该熟悉这张表,每一个状态引擎所对应的变量

clipboard

简单介绍一下vcl的语法

VCL的设计参考了C和Perl语言,因此,对有着C或Perl编程经验者来说,其非常易于理解。其基本语法说明如下:

(1)//、#或/* comment */用于注释

(2)sub $name 定义函数

(3)不支持循环,有内置变量

(4)使用终止语句,没有返回值

(5)域专用

(6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)

编译vcl文件中状态引擎的顺序我们按照默认配置文件的顺序来,此顺序也符合请求处理的基本顺序,当然,为了配合实验也会有些改动。我们来看一张图,可以明确的明白请求的过程:

clipboard[1]

1,首先我们来编写vcl_recv段,

vcl_recv作为进入varnish对请求报文解码后第一个子例程,可以在此处做访问控制,是否查询缓存,以及无法识别的数据的判定。

首先对default.vcl文件复制一份重新改名为test1.vcl

acl purgers {                                        #定义一个acl

"127.0.0.1";

"172.16.0.0"/16;

}

sub vcl_recv {

    if (req.url ~ "^/test.html$") {             #请求首部的url匹配到test.html,

                return(pass);                       #跳过缓存

        }

    if

    if (req.request != "GET" &&             #请求方法不是已知的这7中则发到pipe上去

       req.request != "HEAD" &&

       req.request != "PUT" &&

       req.request != "POST" &&

       req.request != "TRACE" &&

       req.request != "OPTIONS" &&

       req.request != "DELETE") {

       return (pipe);

       }

    if (req.request != "GET" && req.request != "HEAD") {         #不是获取资源的全部跳过缓存,减少无用缓存查询

       return (pass);

     }

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

        if (!client.ip ~ purgers) {                                                   #请求IP不在ACL中定义,则发挥405错误页。

            error 405 "Method not allowed";

          }

        return (lookup);

    }

    return (lookup);

}

那么此时如何加载这个test1让他生效呢?

第一修改配置文件。

第二,利用varnishadm客户端工具。

varnishadm

[root@node1 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082         #进入到管理工具    
200     
-----------------------------    
Varnish Cache CLI 1.0    
-----------------------------    
Linux,2.6.32-431.el6.x86_64,x86_64,-sfile,-smalloc,-hcritbit    
varnish-3.0.5 revision 1a89b1f    
Type ‘help‘ for command list.    
Type ‘quit‘ to close CLI session.    
varnish> vcl.load test1 test1.vcl                                                                    #加载vcl文件

200

VCL compiled.

varnish> vcl.list

200

active 2 boot

available 0 test1

varnish> vcl.use test1

200

varnish> vcl.list

200

available 2 boot

active 0 test1

这样就设定成功了。

为了显示效果我们来配置一下deliver段,给客户端返回时候匹配到缓存信息,以便我我们来查看实验结果。

sub vcl_deliver {

        if (obj.hits > 0) {                                                                        #判断条件缓存匹配次数大于0

                set resp.http.X-Cache = "HIT via" + " " + server.hostname;    #添加HIT via

        } else {

                set resp.http.X-Cache = "MISS via" + " " + server.hostname;   #没有匹配到则添加MISS via

        }

}

访问缓存172.16.18.1.第一次是miss via 之后的访问在缓存有效期内都是HIT via

clipboard[2]

当访问test.html是会被vcl_recv定义的pass匹配到,直接跳过缓存,所以X-cache状态一直是MISS via

clipboard[3]

2,编辑vcl_hash,自定义hash生成时的数据来源。

sub vcl_hash {

   hash_data(req.url);                   #依据req.url来匹配

if (req.http.host) {

   hash_data(req.http.host);          #请求首部的host来缓存

   } else {

   hash_data(server.ip);

   }

   return (hash);

}

3,编辑vcl_hit,从缓存中查找到缓存对象时要执行的操作

sub vcl_hit {                           

    if(req.request == "PURGE"){        #当进入缓存后清理缓存对象,返回Purged;

        purge;

        error 200 "Purged";

        }

}

非pipe请求必经过hit,miss,pass,这三条任意一条,所以也要在其他两路做purge匹配。

4,vcl_miss ,从缓存中查找不到缓存对象时要执行的操作;

sub vcl_miss {               

    if (req.request == "PURGE") {                如果直接不经过缓存,匹配到了PURGE,则返回404说没有进入缓存,否则发往fetch

        error 404 "Not in cache";

}

    return (fetch);

}

5,vcl_pass,用于将请求直接传递至后端主机

vcl_pass {

if (req.request == "PURGE") {              #如果直接是pass,跳过缓存,且匹配到PURGE,

    error 502 "PURGE on a passed object";   

}

    return (pass);

}

6,vcl_fetch,是在请求从后端被成功接收后调用的,可以使用req,bereq,beresp.

可在此处定义cache的缓存有效时长

sub vcl_fetch {

    set beresp.ttl = 360s;                             #修改缓存时长为360s,

    if (req.url ~ ".[jpg|gif|png]$"){                #图片文件缓存时长1h

        set beresp.ttl = 1h;

    }

    if (beresp.status != 200){                        #backend返回状态码不是200,则不缓存数据

        return (hit_for_pass);

    }

    return (deliver);

}

6,sub vcl_deliver ,将用户请求的内容响应给客户端时用到的方法;deliver,在recv之后我们就用过,在里边添加了一个相应给用户的X-cache,是否用到了缓存。复制下来!完善一下!

sub vcl_deliver {

        if (obj.hits > 0) {                                           

                set resp.http.X-Cache = "HIT via" + " " + server.hostname;   

        } else {

                set resp.http.X-Cache = "MISS via" + " " + server.hostname;   

        }

        set resp.http.host = server.hostname;

        retuen (deliver);

}

7,sub vcl_pipe {

    return (pipe);

}

到此一个简单的vcl功能就写好了。

先请求一下curl -X PURGE http://172.16.18.1/index.html

[root@node3 html]# curl -X PURGE http://172.16.18.1/index.html    
<html>    
<head><title>405 Not Allowed</title></head>             #发现和我们定义的Method not allowed不一样,那是为什么呢?

<body bgcolor="white">    
<center><h1>405 Not Allowed</h1></center>    
<hr><center>nginx/1.6.2</center>    
</body>    
</html>

经过查看vcl_recv段发现,我们在PURGE之上就将不是定义的方法送到了pipe.无法到达PURGE.修改如下。将PURGE写在方法判断之前

sub vcl_recv {

    if (req.url ~ "^/test.html$") {          

                return(pass);                     

        }

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

        if (!client.ip ~ purgers) {                                                             

            error 405 "Method not allowed";

          }

        return (lookup);

    }

    if (req.request != "GET" &&                       

       req.request != "HEAD" &&

       req.request != "PUT" &&

       req.request != "POST" &&

       req.request != "TRACE" &&

       req.request != "OPTIONS" &&

       req.request != "DELETE") {

       return (pipe);

       }

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

       return (pass);

     }

    return (lookup);

}

[root@node3 html]# curl -X PURGE http://172.16.18.1/index.html    
<?xml version="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>404 Not in cache</title>    
</head>    
<body>    
<h1>Error 404 Not in cache</h1>    

Not in cache


<h3>Guru Meditation:</h3>    

XID: 506876240


<hr>    

Varnish cache server


</body>    
</html>

这下和我们定义的一样的,看来还得注意判断的先后次序。

下边我们来定义一下有cookie的文件走向。

首先在vcl_resv添加

if (!(req.url ~ "wp-(login|admin)")) {                #所有有cookie的请求都不查缓存

     unset req.http.cookie;

  }

在vcl_fetch中定义抹除cookie           

sub vcl_fetch {

  if (!(req.url ~ "wp-(login|admin)")) {

      unset beresp.http.Set-Cookie;

   }

}

三,后端主机的健康检测

backend web1 {

    .host = "172.16.18.3";

    .port = "80";

    .probe = {

        .url = "/index.html";            #探测什么文件

        .interval = 1s;                     #几秒探测一次

        .window = 5;                      #失败探测多少次

        .threshold = 2;                   #成功探测多少次

}

}

在varnishadm中查看

varnish> backend.list

200

Backend name Refs Admin Probe

default(172.16.18.3,,80) 8 probe Healthy 5/5       

四,varnish使用多台后端主机

Varnish中可以使用director指令将一个或多个近似的后端主机定义为一个逻辑组,并可以指定的调度方式(也叫挑选方法)来轮流将请求发送至这些主机上。不同的director可以使用同一个后端主机,而某director也可以使用“匿名”后端主机(在director中直接进行定义)。每个director都必须有其专用名,且在定义后必须在VCL中进行调用,VCL中任何可以指定后端主机的位置均可以按需将其替换为调用某已定义的director。

注意:当使用自定义的主机时一定要在vcl_recv中指定使用哪个主机,

backend web1 {

    .host = "172.16.18.3";

    .port = "80";

    .probe = {

        .url = "/index.html";           

        .interval = 1s;                   

        .window = 5;                     

        .threshold = 2;                 

}

backend web2 {

    .host = "172.16.18.3";

    .port = "80";

    .probe = {

        .url = "/index.html";          

        .interval = 1s;    

.window = 5;

        .threshold = 2;                 

}

director webservers round-robin {

  {.backend = web1;}

  {.backend = web2;}

}

vcl_recv {                                                        添加下边段落

set req.backend = webservers;                        放在最前边    
}

}

下来访问172.16.18.1验证有没有将请求在两个web服务器上轮询,

clipboard[4]

clipboard[5]

可以看到请求的test.html是轮询的,为什么不请求172.16.18.1呢,应为172.16.18.1有缓存,看不到效果。

varnish的实验就到此了。

本文出自 “aolens·程超” 博客,请务必保留此出处http://aolens.blog.51cto.com/7021142/1558693

varnish+nginx实现单双web服务器缓存