标签:varnish的vcl语法 varnish的内置变量 定义多个后端服务器
一、Varnish的配置语言VCL
Varnish的所有配置都是通过VCL(varnish configure language)来配置的。它是一种基于“域”(domain specific)的简单编程语言,它支持有限的算术运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,也有内置的函数和变量等。使用VCL编写的缓存策略通常保存至.vcl文件中,其需要编译成二进制的格式后才能由varnish调用。事实上,整个缓存策略就是由几个特定的子例程如vcl_recv、vcl_fetch等组成,它们分别在不同的位置(或时间)执行,如果没有事先为某个位置自定义子例程,varnish将会执行默认定义的代码,这些代码就是default.vcl中被注释的代码。
VCL策略在启用前,会由management进程将其转换为C代码,而后再由gcc编译器将C代码编译成二进制程序。编译完成后,management负责将其连接至varnish实例,即child进程。正是由于编译工作在child进程之外完成,它避免了装载错误格式VCL的风险。因此,varnish修改配置的开销非常小,其可以同时保有几份尚在引用的旧版本配置,也能够让新的配置即刻生效。编译后的旧版本配置通常在varnish重启时才会被丢弃,如果需要手动清理,则可以使用varnishadm的vcl.discard命令完成。
二、VCL语法
VCL的设计参考了C和Perl语言,因此,对有着C或Perl编程经验者来说,其非常易于理解。其基本语法说明如下:
(1)//、#或/* comment */用于注释
(2)sub $name 定义函数
(3)不支持循环,有内置变量
(4)使用终止语句(return)将控制权返回给varnish,没有返回值
(5)域专用
(6)操作符:=(赋值)、==(等值比较)、~(模式匹配)、!(取反)、&&(逻辑与)、||(逻辑或)
VCL的函数不接受参数并且没有返回值,因此,其并非真正意义上的函数,这也限定了VCL内部的数据传递只能隐藏在HTTP首部内部进行。VCL的return语句用于将控制权从VCL状态引擎返回给Varnish,而非默认函数,这就是为什么VCL只有终止语句而没有返回值的原因。同时,对于每个“域”来说,可以定义一个或多个终止语句,以告诉Varnish下一步采取何种操作,如查询缓存或不查询缓存等。
三、Varnish的内置函数
(1)、vcl_recv函数
用于接收用户请求,当成功接收用户请求后被调用。通过某种动作来决定如何处理请求。
该函数有如下执行动作:
pass:表示请求不再本地缓存中查找,且进入pass模式,并将处理请求控制权交给vcl_pass函数
pipe:表示请求不再本地缓存中查找,且进入pipe模式,并将请求控制权交给vcl_pipe函数。此模式下不会对客户端做任何的检查或操作,而是在客户端和后端服务器直接建立管道,并将数据直接在这个管道中传输。此时,keep-alive连接中后续的数据也会通过管道进行传输,并且不会出现在任何日志中。
error code [reason]:返回错误代码给客户端并丢弃该请求。Code表示错误代码,如404,405等等。Reason表示错误提示信息。
lookup:表示在缓存中查找请求的对象。并根据查找的结果将请求控制权交给vcl_hit或vcl_miss函数。
(2)、pipe函数
在进入pipe模式时该函数被调用,用于将客户端请求直接传递给后端服务器,在请求和返回的内容没有改变的情况下,将不变的内容直接返回给客户端。直到这个连接关闭。
该函数具有如下执行动作:
error code reason:返回错误代码并丢弃该请求
pipe:
(3)、vcl_pass函数
当vcl_recv函数执行pass动作进入pass模式时该函数被调用,用于将客户端请求直接转发给后端服务器,后端服务器响应给客户端时,不进行缓存。由于直接将请求转发给后端服务器,因此该连接下的响应数据都是最新的。
该函数具有如下执行动作:
error code reason:返回错误代码并丢弃该请求
pass:表示从后端服务器获取数据,并将请求控制权交给vcl_fetch函数
restart:重启整个vcl,并且该请求重新进行检查。即该请求重新接受vcl_recv函数的检查。执行restart动作后,会计算重启计数,当超过max_restarts最大重启计数会返回错误信息
(4)、vcl_hit函数
该函数在执行lookup命令后,如果在缓存中找到请求数据,则自动调用该函数。
该函数具有如下执行动作:
deliver:表示从缓存中找到的数据返回给客户端,并将控制权交给vcl_deliver函数
pass:进入pass模式,并将控制权交给vcl_fetch。这种模式下,虽然在缓存中找到了数据,但是不使用缓存中的数据,而是从后端服务器获取。
error code reason:返回错误代码并丢弃该请求
restart:重启整个vcl,并且该请求重新接受vcl_recv函数的检查。执行restart动作后,会计算重启计数,当超过max_restart最大计数器后会返回错误信息。
(5)、vcl_miss函数
该函数在执行lookup命令后,如果在缓存中没有找到请求数据,则自动调用该函数
该函数具有如下执行动作:
Fetch:表示从后端服务器获取请求数据,并叫控制权交给vcl_fetch
Pass::进入pass模式,并将控制权交给vcl_pass。
Error code reason:表示返回错误代码和信息并丢弃该请求。
Restart:重启整个vcl,并且该请求重新接受vcl_recv函数的检查。执行restart动作后,会计算重启计数,当超过max_restart最大计数器后将返回错误信息。
(6)、vcl_fetch函数
当想从后端服务器获取数据或更新缓存时该函数被调用,并且根据某种动作来判断获取的数据是否被缓存,还是直接返回给客户端。
该函数具有如下动作:
deliver:表示从后端服务器获取到的资源或数据进行缓存。并将控制权交给vcl_deliver函数。
hit_for_pass:表示从后端服务器获取到的数据或资源不进行缓存,且将控制权交给vcl_deliver函数。并且后续对该对象的请求直接交给vcl_pass函数。
error code reason:表示返回错误代码和信息并丢弃该请求。
restart:重启整个vcl,并且该请求重新接受vcl_recv函数的检查。执行restart动作后,会计算重启计数,当超过max_restart最大计数器后将返回错误信息。
(7)、vcl_deliver函数
将请求的数据返回给客户端调用此函数。
该函数具有如下执行动作:
deliver:将请求数据直接返回给客户端
error code reason
restart
(8)、vcl_timeout函数
在缓存内容到期前调用此函数,该函数有如下执行动作:
discard:表示从缓存中清除
fetch:表示从后端服务器获取资源进行更新
(9)、vcl_discard函数
在缓存内容到期后调用此函数,该函数具有如下执行动作:
Keep:表示过期缓存对象仍然保留在缓存中。
Discard:表示从缓存中清除
四、Varnish的工作流程图
Varnish处理请求流程大致可以分为如下几个步骤:
(1)、首先当请求到达时,接受vcl_recv函数的检查,在这个函数中,可以执行pass、pipe、lookup、error操作。
(2)如果在vcl_recv函数执行lookup操作,则会在缓存中查看是否有该缓存对象。如果有,则表示缓存命中,则在接受vcl_hit函数的检查。在该函数下可以将缓存对象直接返回给客户端,即执行deliver操作。也可以不使用本地缓存对象,从后端服务器获取请求对象,即执行pass操作。如果本地没有该缓存对象,则表示缓存丢失,则会接受vcl_miss函数检查。该函数会从后端服务器获取最新资源,即将会执行pass或fetch操作。
(3)如果在vcl_recv函数执行pass操作,则表示不再本地缓存查找,直接从后端服务器进行获取,即将会接受vcl_pass函数的检查。
(4)如果在vcl_recv函数处执行pipe操作,则表示不再本地缓存中查找,并且客户端和后端服务器建立管道,后续客户端的keep-alive连接中的请求数据传输将在管道中进行,并且请求数据接受vcl_pipe函数的检查。直到数据传输完成时关闭该管道连接。
(5)当需要从后端服务器获取资源或数据时,需要调用vcl_fetch函数,并且根据某种条件判断该数据或资源是否缓存在本地,即执行deliver操作;或者直接将该资源返回给客户端,不缓存在本地,即执行hit_for_pass操作
最后,不管是从本地缓存中响应的数据还是从后端原始服务器获取到的数据返回给客户端都需要调用vcl_deliver函数来完成。
五、Vcl的内置变量
Vcl中有许多的内置变量,这些内置变量在不同的阶段被使用。
当varnish接受用户请求时,可以使用的内置变量
req.backend 指定后端主机
server.ip 指定后端服务器ip
client.ip 表示客户端ip
req.request :指定请求方法,如GET,HEAD,POST等
req.url 指定请求的url
req.proto 表示客户端发起请求使用的http协议版本
req.http.<header>: 表示客户端请求报文中的http头部信息
req.restarts:表示请求重启的次数;默认最大值为4
当varnish向后端服务器发送请求时,可以使用的内置变量:
beresp.request: 指定请求的类型,例如GET,HEAD
beresp.url 指定请求的url
beresp.proto 表示客户端发起请求使用的http协议版本
beresp.http.header 表示客户端请求报文中http首部信息
beresp.ttl: 表示缓存的生存时间 ,单位为秒
当后端服务器返回内容时,可以使用的内置变量:
obj.status: 表示返回内容的响应状态码,如200,302等
obj.cacheable: 表示返回内容是否可以缓存,如果http返回的状态码为200,203,301,302,404,410,并且有非0的生存期,则可以缓存。
obj.valid: 是否为有效的http应答;
obj.response:表示返回内容的响应状态信息
obj.ttl: 返回内容的缓存生存时间,单位为秒
当varnish对客户端响应时,可以使用的内置变量:
resp.status: 返回给客户端的状态码
resp.proto:返回给客户端的http的协议版本
resp.http.<header>: 返回给客户响应报文的首部
resp.response: 返回给客户端的http状态信息
六、管理Varnish缓存内容
1、提高缓存命中率
提高缓存命中率有效的途径有:
a、增加缓存对象的生存时间(TTL)
b、加大内存
2、清理缓存
有时候某个缓存的有效时间还没到期时,该缓存对象已经更新了。因此,对于这种情况,对于缓存管理员来说,需要手动清理已经过期或者旧缓存对象。对于Varnish来说,它提供了三种方式来完成这类任务:HTTP修剪(HTTP purging)、禁用某类缓存对象和强制缓存未命中(forced cache misses)
a、HTTP修剪
http pugre功能是通过Varnish的telnet管理端口发送purge指令来清除不需要的缓存对象。其指令格式为:
/usr/local/varnish/bin/varnishadm -T 192.168.0.102:2000 purge.url <REGEXP>
REGEXP:是基于正则表达式匹配的url
如:# /usr/local/varnish/bin/varnishadm –T 192.168.0.102:2000 purge.url /a/varnish1.html
删除所有的缓存对象,可以使用如下指令
如:# /usr/local/varnish/bin/varnishadm –T 192.168.0.102:2000 purge.url ^.*$
查看最近删除的缓存对象列表,可以使用如下命令
如:# /usr/local/varnish/bin/varnishadm –T 192.168.0.102:2000 purge.list
除了在命令行中删除缓存对象这种方式外,可以在通过登录到telnet的管理界面中进行删除动作。如:
[root@varnish-server ~]#telnet 192.168.0.102 2000
Trying 192.168.0.103...
Connected to localhost.localdomain (192.168.0.103).
Escape character is ‘^]‘.
200 154
-----------------------------
Varnish HTTP accelerator CLI.
-----------------------------
Type ‘help‘ for command list.
Type ‘quit‘ to close CLI session.
purge.url /a/mz/2010/0421/11.html #这里是清除这个页面缓存
200 0
purge.url ^/zm/a/d.*$ #这里是清除/zm/a/d/目录下所有以字母d开头的缓存页面
200 0
b、强制缓存未命中
在vcl_recv中使用return(pass)能够强制到上游服务器取得请求的内容,但这也会导致无法将其缓存。使用purge会移除旧的缓存对象,但如果上游服务器宕机而无法取得新版本的内容时,此内容将无法再响应给客户端。使用req.has_always_miss=ture,可以让Varnish在缓存中搜寻相应的内容但却总是回应“未命中”,于是vcl_miss将后续地负责启动vcl_fetch从上游服务器取得新内容,并以新内容缓存覆盖旧内容。此时,如果上游服务器宕机或未响应,旧的内容将保持原状,并能够继续服务于那些未使用req.has_always_miss=true的客户端,直到其过期失效或由其它方法移除。
c、禁用某类缓存对象(banning)
ban()操作是在Varnish 3中才有的,Varnish 2中的purge()操作在Varnish 3中被替换为了ban()操作,而Varnish 3也使用了purge操作,但为其赋予了新的功能。ban()这个操作有人说支持也有人反对,因此,对于这种方式暂且不说。
七、Varnish的后端存储类型
varnish支持多种不同类型的后端存储,这可以在varnishd启动时使用-s选项指定。后端存储的类型包括:
(1)file:使用特定的文件存储全部的缓存数据,并通过操作系统的mmap()系统调用将整个缓存文件映射至内存区域(如果条件允许);
(2)malloc:使用malloc()库调用在varnish启动时向操作系统申请指定大小的内存空间以存储缓存对象;
(3)persistent(experimental):与file的功能相同,但可以持久存储数据(即重启varnish数据时不会被清除);仍处于测试期;
varnish无法追踪某缓存对象是否存入了缓存文件,从而也就无从得知磁盘上的缓存文件是否可用,因此,file存储方法在varnish停止或重启时会清除数据。而persistent方法的出现对此有了一个弥补,但persistent仍处于测试阶段,例如目前尚无法有效处理要缓存对象总体大小超出缓存空间的情况,所以,其仅适用于有着巨大缓存空间的场景。
选择使用合适的存储方式有助于提升系统性,从经验的角度来看,建议在内存空间足以存储所有的缓存对象时使用malloc的方法,反之,file存储将有着更好的性能的表现。然而,需要注意的是,varnishd实际上使用的空间比使用-s选项指定的缓存空间更大,一般说来,其需要为每个缓存对象多使用差不多1K左右的存储空间,这意味着,对于100万个缓存对象的场景来说,其使用的缓存空间将超出指定大小1G左右。另外,为了保存数据结构等,varnish自身也会占去不小的内存空间。
为varnishd指定使用的缓存类型时,-s选项可接受的参数格式如下:
malloc[,size] 或
file[,path[,size[,granularity]]] 或
persistent,path,size {experimental}
file中的granularity用于设定缓存空间分配单位,默认单位是字节,所有其它的大小都会被圆整。
八、Varnish的后端状态检测
Varnish可以检测后端主机的健康状态,在判定后端主机失效时能自动将其从可用后端主机列表中移除,而一旦其重新变得可用还可以自动将其设定为可用。为了避免误判,Varnish在探测后端主机的健康状态发生转变时(比如某次探测时某后端主机突然成为不可用状态),通常需要连续执行几次探测均为新状态才将其标记为转换后的状态。
Varnish检测后端服务器的健康状况是通过.probe进行设定,其结果可由req.backend.healthy变量获取,也可通过varnishlog中的Backend_health查看或varnishadm的debug.health查看。
Varnish检测后端服务器健康状况的配置实例:
backend web1 {
.host = "www.xsl.com";
.probe = {
.url = "/.healthtest.html";
.interval = 1s;
.window = 5;
.threshold = 2;
}
}
.probe中的探测指令常用的有:
(1) .url:探测后端主机健康状态时请求的URL,默认为“/”;
(2) .request: 探测后端主机健康状态时所请求内容的详细格式,定义后,它会替换.url指定的探测方式;比如:
.request =
"GET /.healthtest.html HTTP/1.1"
"Host: www.magedu.com"
"Connection: close";
(3) .window:设定在判定后端主机健康状态时基于最近多少次的探测来进行,默认是8;
(4) .threshold:在.window中指定的次数中,至少有多少次是成功的才判定后端主机是健康运行;默认是3;
(5) .initial:Varnish启动时对后端主机至少需要多少次的成功探测,默认同.threshold;
(6) .expected_response:期望后端主机响应的状态码,默认为200;
(7) .interval:探测请求的发送周期,默认为5秒;
(8) .timeout:每次探测请求的过期时长,默认为2秒;
因此,对于上例中表示每隔1秒对此后端主机www.xsl.com探测一次,请求的URL为http://www.xsl.com/.healthtest.html,在最近5次的探测请求中至少有2次是成功的(响应码为200)就判定此后端主机为正常工作状态。
九、Varnish定义多后端主机
Varnish中可以使用director指令将一个或多个近似的后端主机定义为一个逻辑组,并可以指定相应的调度方式(也叫挑选方法)来轮流将请求发送至这些主机上。不同的director可以使用同一个后端主机,而某director也可以使用“匿名”后端主机(在director中直接进行定义)。每个director都必须有其专用名,且在定义后必须在VCL中进行调用,VCL中任何可以指定后端主机的位置均可以按需将其替换为调用某已定义的director。
定义多个后端主机的配置实例
.backend web1 { #显示定义一台后端服务器
.host = “backend1.xsl.com”;
.port = “80”;
}
director webserver random { #定义一个后端服务器逻辑组,其调度方式为random(即随机)
.retries = 5;
{
.backend = web1;
.weight =2;
}
{
.backend = { #定义一个匿名后端主机
.host = “backend2.xsl.com”;
.port = ‘80’;
}
.weight = 3;
}
}
对于上例而言,web1为显示定义的后端主机。如果有多台的话,需要使用director指令来定义。在上例中,使用director指令定义了一个逻辑组叫做webserver。其中webserver组中需要指定后端服务器的地址及其ip等参数。在webserver组中,定义了2个后端服务器,web1为显示定义的后端主机,“backend2.xsl.com”为匿名主机。
使用director定义某个逻辑组时,由于有多台主机,因此,需要指定调度方式,以便将请求转给相应的后端服务器。director中有2种调调方式:
round-robin:轮调,即请求依次循环的转发给下一个后端主机。该调度方式没有其他参数,只需要知道后端主机即可。
random:随机调度,即从后端主机中随机挑选一台服务器对请求进行响应。在random方式下需要为每一个后端主机指定其weight值。Varnish 2.1.0后,random挑选方法又多了两种变化形式client和hash。client类型的director使用client.identity作为挑选因子,这意味着client.identity相同的请求都将被发送至同一个后端主机。client.identity默认为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端主机。
在director级别下,还可以使用.retries参数来设定查找一个健康的后端主机的尝试次数。
本文出自 “linux学习之路” 博客,谢绝转载!
标签:varnish的vcl语法 varnish的内置变量 定义多个后端服务器
原文地址:http://xslwahaha.blog.51cto.com/4738972/1652971