varnish

一、简介

   Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang 使用3台Varnish代替了原来的12台Squid,性能比以前更好。

   Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两种:内存与硬盘。但现在计算机系统的内存除了主存外,还包括了CPU内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此Squid Cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,这就是 Varnish cache设计架构。

   varnish项目是2006年发布的第一个版本0.9.距今已经八年多了,此文档之前也提过varnish还不稳定,那是2007年时候编写的,经过varnish开发团队和网友们的辛苦耕耘,现在的varnish已经很健壮。很多门户网站已经部署了varnish,并且反应都很好,甚至反应比squid还稳定,且效率更高,资源占用更少。相信在反向代理,web加速方面,varnish已经有足够能力代替squid。

   varnish的官网为https://www.varnish-cache.org,rpm,rpm包的下载位置为:http://repo.varnish-cache.org。

二、关于Varnish

1.varnish系统架构

   varnish主要运行两个进程:Management进程和Child进程(也叫Cache进程)。

   Management进程主要实现应用新的配置、编译VCL、监控varnish、初始化varnish以及提供一个命令行接口等。Management进程会每隔一段时间探测一下Child进程以判断其是否正常运行,如果在指定的时长内未得到Child进程的回应,Mangagement将会重启此Child进程。

   Child进程包含多种类型的线程,常见的如:

       Acceptor进程:接受新的连接请求并响应

       worker进程:child进程会为每个用户启动一个worker进程,因此,在高并发的场景中可能会出现数百个worker进程甚至更多

       Expiry进程:从缓存中清理过期内容

       Varnish依赖“工作区(workspace)”以降低线程在申请或修改内存时出现竞争的可能性。在varnish内部有多种不同的工作区,其中最关键的当属用于管理会话数据的session工作区

2.varnish日志

   为了与系统的其他部分进行交互,Child进程使用了可以通过文件系统接口进行访问的共享内存日志(shared memory log),因此,如果某线程需要记录信息,其仅需要持有一个锁,而后向共享内存中的某内存区域写入数据,再释放持有的锁即可。而为了减少竞争,每个worker线程都使用了日志数据缓存

   共享内存大小一般为90M,其分为两部分,前一部分为计数器,后半部分为客户端请求的数据。varnish通过了多个不同的工具,如varnishlog、varnishncsa或varnishstst等来分析共享内存日志中的信息并能够以指定的方式进行显示

   3.varnish的后端存储

     varnish支持多种不同类型的后端存储。这可以在varnish启动时使用-s选项指定。后端存储的类型包括

     (1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用整个缓存文件映射至内存区域(如果条件允许)

     (2)mallco: 使用mallco()库调用在varnish启动时向操作系统申请指定的大小的内存空间以存储缓存数据

     (3)persistent(experimental):与file的功能相同,但是可以持久存储数据(即重启varnish时数据不会被清楚),仍处于测试阶段

     varnish无法追踪某缓存对象是否存入了缓存文件,而后也就无法得知磁盘上的缓存文件是否可用,因此,file存储在varnish停止或重启是会清除数据。而persistent方法的出现对此有一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所有,其仅适用于有着巨大缓存空间的场景。

    选择使用合适的存储方式有助于途胜系统性能,从经验的角度来看,建议在内存空间足以存储所有数据的缓存对象时使用malloc的方法,反之,file存储将会有着更好的性能表现,然而,需要注意的是,varnishd实际上是用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1k左右的存储空间,这意味着,对于100万个缓存对象来说,其使用的缓存空间将超出指定大小1G左右,另外,为了保存数据结构等,varnish自身也会占去不少的内存空间。

    为varnish指定使用的缓存类型时,-s选项可接受的参数格式如下:

       malloc[,size]或file[,path[,size[,granularity]]]或persistent,path,size{experimental}

三、VCL

   1.简介

     VCL(Varnish Configuration Language)是varnish配置缓存策略的工具,它是一种基于“域”(domain specific)的简单编程语言,他支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也要内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能有varnish调用。事实上,整个缓存策略就是由几个特定的子历程如vcl_recv、vcl_fetch等组成,他们分别在不同的位置(或时间)执行,如果没有实现为某个位置自定义子例程,varnish将会执行默认的定义

    VCL策略在启用前,会由management进程将其转换为C代码,而后再有gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即Child进程。正式由于编译工作在child进程之外完成,它避免了转载错误格式VCL的风险,因此,varnish修改配置的开销非常小,其可以同时保有几分尚在引用的旧版本配置,也能够让新的配置即刻生效,编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令来完成

2.VCL状态引擎

    在VCL状态引擎中,状态之间具有相关性,但彼此间互相隔离,每个引擎使用return(x)来退出当前状态并指示varnish进入下一个状态

    varnish开始处理一个请求时,首先需要分析HTTP请求本身,比如从首部获取请求方法、验证其是否为一个合法的HTTP请求等,当这些基本分析结束后就需要做出第一个决策,即varnish是否从缓存中查找请求的资源,这个决定的实现则需要有VCL来完成,简单来说,要有vcl_recv方法来完成,如果说管理员没有定义vcl_recv函数,varnish将会执行默认的vcl_recv函数,然而,即便管理员自定义了vcl_recv,但如果没有为自定义的vcl_recv函数指定其终止操作(terminating),其仍将会指定默认的vcl_recv函数,事实上,varnish官方强烈建议让varnish执行默认的vcl_recv以便处理自定义vcl_recv函数中可能出现的漏洞

3.VCL语法

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

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

    (2)sub $name 定义函数

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

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

    (5)域专用

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

    VCL的函数不接受参数并且没有返回值,因此,其并非真正意义上的函数,这也限定了VCL内部的数据传递只能隐藏在HTTP首部内部进行。VCL的return语句用于将控制权从VCL状态引擎返回给varnish,而非默认函数,这就是为什么VCL只有终止语句而没有返回值的原因,同时,对于每个“域”来说,可以定义一个或多个终止语句,以告诉varnish下一步采取何种操作,如查询缓存或不查询缓存

4.VCL的内置函数

     VCL提供了结果函数来实现字符串的修改,如添加bans,重启VCL状态引擎因将控制权转回varnish等

    regsub(str,reget,sub):基于正则表达式搜索指定的字符串并将其替换成指定的字符串,只替换匹配到的第一个

    regsuball(str,reget,sub):基于正则表达式搜索指定的字符串并将其统统替换成指定的字符串

    ban(expression):

    ban_url(regex):Bans所有其URL能够由regex匹配的缓存对象

    purge:从缓存中挑选出某对象以及其相关变种一并删除,这可以通过通过HYTP协议的PURGE方法完成

    hash_data(str):

    return():当某个VCL与运行结束时,将控制权返回给Varnish,并指示Varnish如何进行后续的操作:其可以返回的指令包括:lookup、pass、pipe、hit_for_pass、fetch、deliver和hash等:但某特定域可能技能返回某些特定的指令,而非前面列出的全部指令:

    return(restart):重新运行整个VCL,即重新从vcl_recv开始进行处理;每一次重启都会增加req.restaets变量中的值,而max_restaets参数则用于限定最大重启次数

5.vcl_recv

     vcl_recv是在varnish完成对请求报文的解码为基本数据结构后第一个要指定的子例程,他通常有四个主要用途:

     (1)修改客户端数据以减少缓存对象差异性,比如删除URL中的www.等字符串

      (2)基于客户端数据选用缓存策略:比如仅缓存特定的额URL请求、不缓存POST请求等

     (3)为某web应用程序执行URL重写

     (4)挑选合适的后端服务器;

    可以使用下面的终止语句,即通过return()向varnish返回指示操作

      pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

      pipe:不对客户端进行检查或做出任何操作,而是在客户端与后端服务器之间建立专业“通道”,并直接将数据在二者之间进行传送:此时,keep-alive连接中后续传送的数据也都将在通过此管道进行直接传送,并不会出现在任何日志中

      lookup:在缓存中查找用户请求的对象,如果缓存中没有其指定的对象,后续操作很可能会将其请求的对象进行缓存

      error:有varnish自己合成一个响应报文,一般是响应一个错误类信息、重定向类信息或缓存均衡器返回的后端web服务器健康状态检查类信息

     vcl_recv也可以通过精巧的策略完成一定意义上的安全功能,以将某特定的***扼杀于摇篮中,同时,它也可以检查出一些拼写的错误并将其进行修改

     varnish默认的vcl_recv专门设计用来实现安全的缓策略,它主要完成两种功能:

       (1)仅处理可以识别的HTTP方法,并且只缓存GET和HEAD方法

       (2)不缓存任何用户特有的数据

     安全起见,一般都在自定义的vcl_recv中不要使用return()终止语句,而是再由默认vcl_recv进行处理,并有其做出响应的的处理决策

6.vcl_fetch

     如前面所述,想对于vcl_recv是根据客户端的请求做出缓存策略来说,vcl_fetch则是根据服务器端的响应做出缓存决策,在任何VCL状态引擎中发挥pass操作都将有vcl_fetch进行后续处理。vcl_fetch中有许多可用的内置变量,比如最常见的用于定义某对象缓存时长的beresp.ttl变量,通过return()返回给varnish的操作指令有:

       deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver)

       hit_for_pass:不缓存此对象,但可以导致后续对此对象的请求直接送达到vcl_pass进行处理

       restart:重启整个VCL,并增加重启次数,超出max_restarts限定的最大重启次数将会发挥错误信息

       error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

      默认的vcl_fetch放弃了缓存任何使用了Set-Cookie首部的响应

7.vcl_deliver

     在缓存中找到缓存内容,发送给客户端时调用此参数,通过return()返回给varnish的操作指令有:  

       deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver)

       error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

8.val_pass

      此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,后端主机应答数据后发送给客户端,但是不缓存任何数据,在当前连接下,每次都是犯回最新的内容,通过return()返回给varnish的操作指令有:  

        error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

        pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

9.vcl_pipe

       不对客户端进行检查或做出任何操作,而是在客户端与后端服务器之间建立专业“通道”,并直接将数据在二者之间进行传送:此时,keep-alive连接中后续传送的数据也都将在通过此管道进行直接传送,并不会出现在任何日志中,通过return()返回给varnish的操作指令有:  

         error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

        pipe:不对客户端进行检查或做出任何操作,而是在客户端与后端服务器之间建立专业“通道”,并直接将数据在二者之间进行传送:此时,keep-alive连接中后续传送的数据也都将在通过此管道进行直接传送,并不会出现在任何日志中

10.lookup

      表示在缓存里查找被请求的对象,并且根据查找的数据把控制权交给vcl_miss或vcl_hit

11.vcl_hit

       在执行lookup指令后,如果在缓存中找到请求的内容,将自动调用此函数,通过return()返回给varnish的操作指令有:

        deliver:缓存此对象,并将其发送给客户端(经由vcl_deliver)

        error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

         pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

12.vcl_miss函数

      在执行lookup指令后,如果在缓存中找不到请求的内容,将自动调用此函数,此函数可以判断是否在后端服务器上获取内容,通过return()返回给varnish的操作指令有:

         error code [reson]:返回指定的错误代码给客户端并丢弃此请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

         pass:绕过缓存,即不从缓存中查询内容或不将内容存储至缓存中;

13.VCL处理流程图

       通过上面对VCL函数的介绍,大家应该对每个函数实现的功能有一个了解,,起始每个函数之间是有联系的,如下图所示

wKioL1cVu3LCOv4kAAFmr2HtAaw854.jpg 


状态引擎:

1:vcl_recv    2:vcl_pipe   3:vcl_pass   4:vcl_hash    5:vcl_hit   6:vcl_miss   7:vcl_fetch   8:vcl_delier  

9:vcl_error


缓存的处理步骤:

   接受请求---解析请求---查询缓存---新鲜度检查---创建响应报文---发送响应---记录日志

 

缓存的新鲜度检测方法:

  (1)过期时间:

         HTTP/1.0   

             Expires:"Mon, 21 Mar 2016 05:02:19 GMT"   固定时间来检测

                    HTTP/1.1

             Cache-Control:"max-age=900"  这种最多存活时时间来检测

 

  (2)有效性再验证:revalidate

          如果原始内容发生改变,就正常响应,响应码200 

          如果原始内容没改变,则仅相应首部(不带body部分),相应码304Not Modified

          如果原始内容消失,响应为404,些时缓存中cache object 也应该被删除

   

   (3)条件式请求首部:

 

            根据时间戳判断:

     If-Modified-Since: 自从请求的时间之后,请求的资源是否发生过修改,用时间戳验证

     If-Unmodified-Since:自从请求的时间之后,请求的资源是否发没有修改

      

      根据标签来判断:

     If-None-Match :本地缓存中存储的文档的Etag标签是否与服务器文档的Etag不匹配。

     If-Match :本地缓存中存储的文档的Etag标签是否与服务器文档的Etag匹配。

 

yum 安装 varnish

# yum insatll varnish-libs-3.0.4-1.el6.x86_64.rpm varnish-3.0.4-1.el6.x86_64.rpm 

 wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-3.0.5-1.el6.x86_64.rpm 

wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-libs-3.0.5-1.el6.x86_64.rpm

wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-docs-3.0.5-1.el6.x86_64.rpm

1:

# vi /etc/sysconfig/varnish

修改一下参数
VARNISH_LISTEN_PORT=80                     //表示将varnish对外的监听端口改为80

 VARNISH_STORAGE="malloc,100M"             //将数据缓存在内存中,内存大小为100M

其余的使用默认即可


2:

置varnish

     本处使用varnishadm命令行接口来刷新varnish

      命令格式:varnishadm [-n ident] [-t timeout] [-S secretfile] -T [address]:port command [...]

      通过命令行的方式连接至varnishd进行管理操作的工具,指定要连接的varnish实例有两种方法:

       -T [address]:port 来接指定套接字上的实例

       -n ident 连接指定名称的实例

    其运行模式有两种,当不在命令行中给出指定要指定的“command”时,要将进入交互模式,否则,varnish将指定指定的“command”并退出。


# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082

 varnishadm 使用:

   vcl.load

   vcl.use

   vcl.show

   vcl.discard


varnish 一般只对 get head 缓存


backend storage:支持缓存存储内型有3种

         -s type 

        malloc  [,size]   //内存中缓存

    file[,path[,size[,granularity]]]         //一个文件保存所有缓存

    persistent,path,size {experimental}      // 在具体生并环境中不建议用,

 

varnishl 里可用单分支和多分支判断

 

varnish 里可用变量:

 1:常用变量,在任何引擎中都可以用的,

    new           // 获取当前系统的当前时间

   .host          //后端主机的ip

   .port         //后断主机的端口

 

2:用于处理请求阶段

   client.ip                 // 客户机ip

   server.hostname      // 服务器主机名(varnish服务器名)

   server.ip              // 务器主ip   (varnish ip)

   server.port         //服务器端口    (varnish 端口)

 

   req.request    //请求方法

   req.url           // 请求url

   req.porto        //请求协议

   req.backend       //用于服务此次请求的后端主机

   req.backend.healthy   //后端健康状态

   req.http.HEADER    //引用请求报文中指定的首部

   req.hash-always_miss 

   req.hash-ignore_busy

   req.can_gzip      //客户端是否能接受gzip 压缩的内容

   req.restarts     //此请求被重启的请求

 

3: varnish自己 向backend 主机发起请求前可用的变量

   bereq.request    //varnish 对后端口请求方法

   bereq.url            //varnish 对后端口请求url

   bereq.proto       //varnish 对后端请求协议

   bereq.http.HEADER    //varnish 对后端口请求头

   bereq.connect_timeout     //等待与backend主机发起的连接超时时长

 

   4:backend主机的响应报文到达varnish主机后,将其放放置于cache中之前可用的变量。

   beresp.do_stream    // 流式响应

   beresp.do_gzip        //  是否压缩后存入cache

   beresp.do_gunzip    //   是否解压后存入缓存。

   beresp.http.HEADER   // 响应时头

   beresp.proto             // 响应时协议

   beresp.status           //  响应状态码

   beresp.response        // 响应时的原因短语

   beresp.ttl                  // 响应对象的剩余生存时长,单位为秒

   beresp.backend.name   // 相应报文来源的backend名称

   beresp.backend.ip        //   响应时报文来源的backend IP

   beresp.backend.port    //   响应时报文来源的backend 端口

   beresp.storage            //响应的存储后端

  

  5:缓存对象存入的ccache之后可用的变量

obj,proto           //响应时协议

obj.status        // 响应时状态码

obj.response  

obj.hits           //响应时次数

obj.ttl  

obj,http,HEADER    // 响应首部

 

  6:在决定对请求键做hash计算时可用的变量

     req.hash

     

  7:在为客户端准备响应时报文可用变量

   resp.proto

   resp.status

   resp.response

   resp.http.HEADER

 

状态引擎:

  vcl_init: 在装载vcl,用其处理请求之前

  vcl_recv: 请求被接入,但在其分析,处理完成之前。

             是否服务些请求,如何服务,使用那个后端主机服务

  vcl_fetch:从后端口主机收到相应报文之前被调用

      deliver

              error code 给个错误码

             restart 重启请求

       



 

warnish param的查看和修改:

varnish> param.show -l

修改链接池一些值,但是这种方法只对当前有效果

varnish> param.set thread_pool_max 4000      修改线程池个数

200 

 

varnish 线程模型:

 cache-worker 线程

 cache-mian 线程:些线程只有一个,用来启动cache

 ban luker:

 acceptor:

 epoll: 线程池管理

 expire: 清理过期缓存

 

 

thread_pool_add_delay       2 [milliseconds]

thread_pool_add_threshold   2 [requests]

thread_pool_fail_delay      200 [milliseconds]

thread_pool_max             3000 [threads] 单个线程池启动最多线程个数

thread_pool_min             50 [threads]

thread_pool_purge_delay     1000 [milliseconds]  每一秒清理一次缓存,请保留默认

thread_pool_stack           unlimited [bytes]

thread_pool_timeout         120 [seconds]  线程池的超时时间,

thread_pool_workspace       65536 [bytes]  线程池默认使用多少内存,建议默认

thread_pools                2 [pools]     线程池管理

thread_stats_rate           10 [requests]

 

 

varnish的命令行工具:

(1)varnishadm

(2)varnishtop:内存日志区域查看工具

  RxHeader User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebK

it/53

  RxHeader:为tag,基于标签过虑,可用-i-x 选项,

  User-Agent 为起始内容。称为日志消息。用-I-X过滤

-I regexp:仅显示被模式匹配到的条目

-X regexp:仅显示不被模式匹配到的条目

-C:忽略大小写

-d:显示已有日志

 

(3)varnishstat  缓存统计

-l 列出所有字段

-f 统计字段  -f后接的字段名

-x:xml输出格式

-j:json 格式输出

 

配置文件:

sub vcl_deliver {

     if (obj.hits>0) {

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

     } else {

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

     }

     return (deliver);

 }

下面为varnish 配置样本

backend default {

  .host = "192.168.1.105";

  .port = "80";

}

acl purgers {

        "127.0.0.1";

        "192.168.1.0"/24;

}

# Below is a commented-out copy of the default VCL logic.  If you

# redefine any of these subroutines, the built-in logic will be

# appended to your code.

 sub vcl_recv {

     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;

        }

     }


     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" &&

       req.request != "PURGE") {

     #    /* Non-RFC2616 or CONNECT which is weird. */

         return (pipe);

     }

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

      #  /* We only deal with GET and HEAD by default */

         return (pass);

     }

     if (req.http.Authorization || req.http.Cookie) {

  #       /* Not cacheable by default */

         return (pass);

     }

     return (lookup);

 }


# sub vcl_pipe {

#     # Note that only the first request to the backend will have

#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to

#     # have it set for all requests, make sure to have:

#     # set bereq.http.connection = "close";

#     # here.  It is not set by default as it might break some broken web

#     # applications, like IIS with NTLM authentication.

#     return (pipe);

# }

 sub vcl_pass {

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

                error 502 "PURGE on a passed object";

        }

     return (pass);

 }

# sub vcl_hash {

#     hash_data(req.url);

#     if (req.http.host) {

#         hash_data(req.http.host);

#     } else {

#         hash_data(server.ip);

#     }

#     return (hash);

# }

 sub vcl_hit {

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

                purge;

                error 200 "Purged";

        }

     return (deliver);

 }


 sub vcl_miss {

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

                purge;

                error 404 "Not in cache";

        }

     return (fetch);

 }


# sub vcl_fetch {

#     if (beresp.ttl <= 0s ||

#         beresp.http.Set-Cookie ||

#         beresp.http.Vary == "*") {

#               /*

#                * Mark as "Hit-For-Pass" for the next 2 minutes

#                */

#               set beresp.ttl = 120 s;

#               return (hit_for_pass);

#     }

#     return (deliver);

# }

 sub vcl_deliver {

     if (obj.hits>0) {

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

     } else {

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

     }

     return (deliver);


 }


# sub vcl_error {

#     set obj.http.Content-Type = "text/html; charset=utf-8";

#     set obj.http.Retry-After = "5";

#     synthetic {"

# <?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>"} + obj.status + " " + obj.response + {"</title>

#   </head>

#   <body>

#     <h1>Error "} + obj.status + " " + obj.response + {"</h1>

#     <p>"} + obj.response + {"</p>

#     <h3>Guru Meditation:</h3>

#     <p>XID: "} + req.xid + {"</p>

#     <hr>

#     <p>Varnish cache server</p>

#   </body>

# </html>

# "};

#     return (deliver);

# }

# sub vcl_init {

#       return (ok);

# }

# sub vcl_fini {

#       return (ok);


配置范例2:


probe chk {

  .url = "/test.html";

  .window = 5;

  .threshold = 3;

  .interval = 3s;

  .timeout = 1s;

  }

backend web1 {

  .host = "192.168.1.104";

  .port = "80";

  .probe = chk;

}

backend web2 {

  .host = "192.168.1.105";

  .port = "80";

  .probe = chk;

}


director webservers random {

  .retries = 5;

  {

    .backend = web1;

    .weight = 1;

  }


   {

    .backend = web2;

    .weight = 1;

  }

}

acl purgers {

        "127.0.0.1";

        "192.168.1.0"/24;

}

# Below is a commented-out copy of the default VCL logic.  If you

# redefine any of these subroutines, the built-in logic will be

# appended to your code.

 sub vcl_recv {

     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;

        }

     }


     if (req.request ~ "test.html") {

        set req.backend = web1;

        } else {

        set req.backend = webservers;

        }

     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" &&

       req.request != "PURGE") {

     #    /* Non-RFC2616 or CONNECT which is weird. */

         return (pipe);

     }

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

      #  /* We only deal with GET and HEAD by default */

         return (pass);

     }

     if (req.http.Authorization || req.http.Cookie) {

  #       /* Not cacheable by default */

         return (pass);

     }

     return (lookup);

 }


# sub vcl_pipe {

#     # Note that only the first request to the backend will have

#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to

#     # have it set for all requests, make sure to have:

#     # set bereq.http.connection = "close";

#     # here.  It is not set by default as it might break some broken web

#     # applications, like IIS with NTLM authentication.

#     return (pipe);

# }

 sub vcl_pass {

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

                error 502 "PURGE on a passed object";

        }

     return (pass);

 }

# sub vcl_hash {

#     hash_data(req.url);

#     if (req.http.host) {

#         hash_data(req.http.host);

#     } else {

#         hash_data(server.ip);

#     }

#     return (hash);

# }

 sub vcl_hit {

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

                purge;

                error 200 "Purged";

        }

     return (deliver);

 }


 sub vcl_miss {

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

                purge;

                error 404 "Not in cache";

        }

     return (fetch);

 }


# sub vcl_fetch {

#     if (beresp.ttl <= 0s ||

#         beresp.http.Set-Cookie ||

#         beresp.http.Vary == "*") {

#               /*

#                * Mark as "Hit-For-Pass" for the next 2 minutes

#                */

#               set beresp.ttl = 120 s;

#               return (hit_for_pass);

#     }

#     return (deliver);

# }

 sub vcl_deliver {

     if (obj.hits>0) {

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

     } else {

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

     }

     return (deliver);


 }


# sub vcl_error {

#     set obj.http.Content-Type = "text/html; charset=utf-8";

#     set obj.http.Retry-After = "5";

#     synthetic {"

# <?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>"} + obj.status + " " + obj.response + {"</title>

#   </head>

#   <body>

#     <h1>Error "} + obj.status + " " + obj.response + {"</h1>

#     <p>"} + obj.response + {"</p>

#     <h3>Guru Meditation:</h3>

#     <p>XID: "} + req.xid + {"</p>

#     <hr>

#     <p>Varnish cache server</p>

#   </body>

# </html>

# "};

#     return (deliver);

# }

# sub vcl_init {

#       return (ok);

# }

# sub vcl_fini {

#       return (ok);

# }