一、varnish简介

Varnish是一款高性能且开源的反向代理服务器和HTTP加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的squidweb缓存服务器相比,varnish具有性能更高、速度更快、管理更加方便等诸多优点,使得越来越多的大型网站开始尝试使用varnish作为缓存服务器。

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

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

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

Acceptor线程:接受新的连接请求并并回应。

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

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

二、vcl简介

VarnishConfigurationLanguage(VCL):varmish配置语言;varnish配置缓存策略工具。是一种基于“域(domainspecific)”的简单编程语言,支持有限的算数运算和逻辑运算操作、允许使用正则表达式进行字符串匹配、允许用户使用set自定义变量、支持if判断语句,具有内部函数和变量。使用VCL编写的缓存策略通常保存至.vcl文件中,需要编译成二进制格式后才能有vainish调用。

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

三、VCL内置函数
1.vcl_recv函数
用于接收和处理请求,当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。
此函数一般以如下几个关键字结束:
pass:表示进入pass模式,把请求控制权交给vcl_pass函数。
pipe:表示进入pipe模式,把请求控制权交给vcl_pipe函数。
errorcode[reason]:表示返回“code”给客户端,并放弃处理该请求,“code”是错误标识,例如200、405等,“reason”是错误提示信息。

2.vcl_pipe函数

此函数在进入pipe模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个链接关闭。
此函数一般以如下几个关键字结束:
errorcode[reason]
pipe:表示进入pipe模式,把请求控制权交给vcl_pipe函数。

3.vcl_hit函数
在执行lookup指令后,如果在缓存中找到请求的内容,将自动调用该函数。
此函数一般以如下几个关键字结束:
deliver:表示将找到的内容发送给客户端,并把控制权交给函数vcl_deliver。
errorcode[reason]
pass

4.vcl_miss函数在执行lookup指令后,如果没有在缓存中找到请求的内容时自动调用该方法,此函数可以用于判断是否需要从后端服务器取内容。
此函数一般以如下几个关键字结束:
fetch:表示从后端获取请求的内容,并把控制权交给vcl_fetch函数。
errorcode[reason]
pass表示进入pass模式,把请求控制权交给vcl_pass函数。

5.vcl_pass函数此函数在进入pass模式时被调用,用于将请求直接传递至后端主机,后端主机应答数据后送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容。
此函数一般以如下几个关键字结束:
errorcode[reason]
pass表示进入pass模式,把请求控制权交给vcl_pass函数。
lookup表示在缓存里查找被请求的对象,并且根据查找的结果把控制权交给函数vcl_hit或者函数vcl_miss。
6.vcl_fetch函数在从后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是否将内容放入缓存,还是直接返回给客户端。
此函数一般以如下几个关键字结束:
errorcode[reason]
pass表示进入pass模式,把请求控制权交给vcl_pass函数。
Deliver表示将找到的内容发送给客户端,并把控制权交给函数vcl_deliver。

7.vcl_deliver函数在缓存中找到请求的内容后,发送给客户端前调用此方法。此函数一般以如下几个关键字结束:
errorcode[reason]
deliver表示将找到的内容发送给客户端,并把控制权交给函数vcl_deliver。

8.vcl_timeout函数此函数在缓存内容到期前调用。一般以如下几个关键字结束:
discard:表示从缓存中清除该内容。
Fetch表示从后端获取请求的内容,并把控制权交给vcl_fetch函数。

9.vcl_discard函数在缓存内容到期后或缓存空间不够时,自动调用该方法,一般以如下几个关键字结束:
keep:表示将内容继续保留在缓存中。
Discard:表示将缓存中的内容手动清除。

四、VCL处理流程图

varnish原理解析_varnish原理  缓存 状态引擎 v

上图转载于:http://songknight.blog.51cto.com/2599480/692239

状态引擎

<1>Receive状态请求处理的入口状态,根据VCL规则判断该请求应该是PassPipe,或者进入Lookup查找本地缓存。

<2>Lookup状态进入此状态后,会在hash表中查找数据,若找到,则进入Hit状态,否则进入miss状态。

<3>Pass状态在此状态下,会进入后端请求,即进入fetch状态。

<4>Fetch状态Fetch状态下,对请求进行后端的获取,发送请求,获得数据,并进行本地的存储。

<5>Deliver状态将获取到的数据发送给客户端,然后完成本次请求。

五、VCL内置变量

1.Backend段使用的变量。

.host:后端服务的主机名或IP

.port:后端服务服务名或端口

2.当请求到达后,可以使用的公用变量如下:

req.backend指定对应的后端主机

server.ip服务器端IP

client.ip客户端IP

req.request指定请求的类型,egGETHEADPOST

req.url请求的地址

req.proto客户端发起请求的HTTP协议版本

req.http.header对应请求中的http头部信息

req.restarts请求重启的次数,默认最大值为4

3.Varnish在向后端主机请求时,可以使用的公用变量如下:

beresp.request:指定请求的类型,egGETHEAD

beresp.url指定请求的地址

beresp.proto客户端发起请求的HTTP协议版本

beresp.http.header对应请求中的http头部信息

beresp.ttl缓存的生存周期,也就是cache保留多长时间,默认单位是秒s

4.cache或者后端主机获取内容后,可以使用的公用变量如下:

obj.status返回内容的请求状态代码,eg200302504

obj.cacheable返回的内容是否可以缓存如果HTTP返回是200203300301302404410等,并且有非0的生存期,则可以缓存

obj.valid是否是有效的HTTP应答

obj.response返回内容的请求状态信息

obj.proto返回内容的HTTP协议版本

obj.ttl返回内容的生存周期,也就是缓存时间,默认单位秒s

obj.lastuse返回上一次请求到现在的间隔时间,默认单位秒s

obj.hits

5.对客户端应答时,可以使用的公用变量如

resp.status返回给客户端的HTTP状态代码

resp.proto返回给客户端的HTTP协议版本

resp.http.header返回给客户端的HTTP头部信息

resp.response返回给客户端的HTTP状态信息

六、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的director支持的调度方法中比较简单的有round-robin和random两种。其中,round-robin类型没有任何参数,只需要为其指定各后端主机即可,挑选方式为“轮叫”,并在某后端主机故障时不再将其视作挑选对象;

random随机从可用后端主机中进行挑选,每一个后端主机都需要一个.weight参数以指定其权重,同时还可以director级别使用.retires参数来设定查找一个健康后端主机时的尝试次数。

varnish2.1.0版本以后,random挑选方法又多了两种变化形式client和hash。client类型的director使用client.identity作为挑选因子,因此client.identity相同的请求都将被发送至同一个后端主机。client.identity默认为cliet.ip,但也可以在VCL中将其修改为所需要的标识符。类似地,hash类型的director使用hash数据作为挑选因子,这意味着对同一个URL的请求将被发往同一个后端主机,其常用于多级缓存的场景中。然而,无论是client还hash,当其倾向于使用后端主机不可用时将会重新挑选新的后端其机。