既然Varnish需要在多台服务器上缓存数据,就需要Varnish映射所有的URL到一台单独的主机。
该块配置用于定义一台Varnish默认访问的后端服务器,当Varnish需要从后端服务器获取数据时,就会访问自己的80端口。
当然Varnish也可以定义多台后端服务器实现负载均衡的目的。
.connect_timeout定义的是等待连接后端的时间
.first_byte_timeout定义的是等待从backend传输过来的第一个字节的时间
.between_bytes_timeout 定义的是两个字节的间隔时间
当然还可以增加一个backend,用于访问本机的8090端口,假设通过该端口提供图片服务。
当匹配img的URL时,需把请求发送到上面定义的backend img,其他的请求发送到backend webserver。
Varnish不仅仅可以定义多个backend,还可以把多个backend合成一个组,使用循环的方式把请求分配给组中的backends。并且Varnish会根据健康检查情况来判断后端服务器是否正常提供服务。
Varnish使用区域语言VCL来管理定义Varnish的存取策略。VCL语法简单,跟Perl比较相似,可以使用多种运算符如"="、"=="、"!,&&,!!"等形式;也可以使用正则表达式来进行匹配,还可以使用"set"来指定变量。当执行VCL时,Varnish会先把VCL转换成二进制代码。
有一点要注意,"\"字符在VCL里没有什么特别的含义,这点和其他语言不同。另外,VCL只是配置语言,并不是真正的编程语言,所以没有循环和自定义变量。
为了可以更好地对Varnish进行配置调整,需要了解Varnish的配置语法,也就是VCL语言。下面对VCL常用的一些函数和变量进行介绍。
(1)vcl_recv模块
用于接收和处理请求。当请求成功被调用后,Varnish通过判断请求的数据来决定如何处理请求。此模块一般以如下几个关键字结束。
pass:表示进入pass模式,把请求交给vcl_pass模块处理。
pipe:表示进入pipe模式,把请求交给vcl_pipe模块处理。
error code [reason]:表示把错误标识返回给客户端,并放弃处理该请求。错误标识包括200、405等。"reason"是对错误的提示信息。
(2)vcl_pipe模块
此模块在请求进入pipe模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,也就是在当前连接未关闭时,服务器将不变的内容返回给客户端,直到该连接被关闭。
(3)vcl_pass模块
此模块表示当请求被pass后,用于将请求直接传递至后端应用服务器。后端应用服务器在接收请求后将数据发送给客户端,但不进行任何数据的缓存,在当前连接下每次都返回最新的内容。
(4)lookup
一个请求在vcl_recv中被lookup后,Varnish将在缓存中提取数据。如果缓存中有相应的数据,就把控制权交给vcl_hit模块;如果缓存中没有相应的数据,请求将被设置为pass并将其交给vcl_miss模块。
(5)vcl_hit模块
执行lookup指令后,Varnish在缓存中找到请求的内容后将自动调用该模块。
在此模块中,deliver表示将找到的数据发送给客户端,并把控制权交给vcl_deliver模块。
(6)vcl_miss模块
执行lookup后,Varnish在缓存中没有找到请求的内容时会自动调用该方法。此模块可以用于判断是否需要从后端服务器获取内容。
在此模块中,fetch表示从后端获取请求的数据,并把控制权交给vcl_fetch模块。
(7)vcl_fetch模块
在后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端。
(8)vcl_deliver模块
当一个没有被缓存的数据交付给客户端的时候被调用。
(9)vcl_timeout 模块
在缓存数据到期前调用此模块。
在此模块中,discard表示从缓存中清除到期数据。
(10)vcl_discard模块
在缓存数据到期后或缓存空间不够时,自动调用该模块。
在此模块中keep表示将数据继续保留在缓存中。
这段条件判断用于对aaa.com域名进行缓存加速,aaa.com是泛指概念,也就是说所有以aaa.com结尾的域名都进行缓存。而if (req.request != "GET" && req.request != "HEAD") 表示"如果请求的类型不是GET与HEAD",则返回错误码404。
这条规则的意思是清除服务器上/images目录下的所有缓存,当这个请求在后端服务器生效时,如果访问的URL匹配这个规则,那么头信息中的cookie就会被删除。
因为Squid、Varnish都会把客户端的IP地址放在HTTP_X_FORWARDED_FOR里面传给后端的Web服务器,所以后端的Web程序都要对其进行调用。
该if判断用于对请求类型是GET,并且请求的URL以png、swf、txt、gif、css、js等结尾时,则进行缓存,缓存时间为180秒。其他缓存为30天。
这个模块定义的是添加一个Header标识,以判断缓存是否命中。
最后这个模块定义了访问错误页面时的返回信息。
现在varnish配置基本完成,可以在8080端口上启动varnish,并进行一些基本的测试。
Varnish缓存的配置
简单的配置文件内容如下:
Varnish 简介
Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的 squid 相比,varnish 具有性能更高、速度更快、管理更加方便等诸多优点,很多大型的网站都开始尝试使用 varnish 来替换 squid,这些都促进 varnish 迅速发展起来。
挪威的最大的在线报纸 Verdens Gang(vg.no) 使用 3 台 Varnish 代替了原来的 12 台 Squid,性能比以前更好,这是 Varnish 最成功的应用案例。
回页首
Varnish 文件缓存的工作流程
Varnish 与一般服务器软件类似,分为 master 进程和 child 进程。Master 进程读入存储配置文件,调用合适的存储类型,然后创建 / 读入相应大小的缓存文件,接着 master 初始化管理该存储空间的结构体,然后 fork 并监控 child 进程。Child 进程在主线程的初始化的过程中,将前面打开的存储文件整个 mmap 到内存中,此时创建并初始化空闲结构体,挂到存储管理结构体,以待分配。Child 进程分配若干线程进行工作,主要包括一些管理线程和很多 worker 线程。
接着,开始真正的工作,varnish 的某个负责接收新 HTTP 连接线程开始等待用户,如果有新的 HTTP 连接过来,它总负责接收,然后唤醒某个等待中的线程,并把具体的处理过程交给它。Worker 线程读入 HTTP 请求的 URI,查找已有的 object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。
分配缓存的过程是这样的:它根据所读到 object 的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个 object 的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据 LRU 机制,把最旧的 object 释放掉。
释放缓存的过程是这样的:有一个超时线程,检测缓存中所有 object 的生存期,如果超初设定的 TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。
整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的 object 都考虑是在内存中,如果系统内存不足,系统会自动将其换到 swap 空间,而不需要 varnish 程序去控制。
回页首
Varnish 安装
下载 varnish 安装包
建议下载最新稳定版本(现在最新 varnish 版本为 3.0.2),varnish 提供源代码安装包和可执行程序安装包,按照您的习惯下载适合您平台的任一安装包即可。
安装 varnish
源代码安装包安装
首先安装 pcre 库,pcre 库是为兼容正则表达式,如果不安装,在安装 varnish2.0 版本以上时,会提示找不到 pcre 库。以下是 pcre 的安装过程,其代码如清单 1 所示:
tar zxvf pcre.tar.gz cd pcre/ ./configure --prefix=/usr/local/pcre/ Make && make install |
安装 varnish,其代码如清单 2 所示:
tar xzvf varnish-3.0.2.tar.gz cd varnish-3.0.2 export PKG_CONFIG_PATH =/usr/local/pcre/lib/pkgconfig ./configure --prefix=/usr/local/varnish make make install |
可执行程序安装包安装
RedHat 系统环境下的安装 varnish,您需要安装以下软件:automake、autoconf、libtool、ncurses-devel、libxslt、groff、pcre-devel、pkgconfig,然后进行 varnish 的安装,安装代码如清单 3 所示:
rpm -i varnish-2.1.4-2.el5.x86_64.rpm |
启动 varnish
varnishd -f /etc/varnish/default.vcl -s file,/var/varnish_cache,1G \ -T 127.0.0.1:2000 -a 0.0.0.0:9082 |
各参数的含义如下:
-f 指定 varnish 的配置文件位置
-s 指定 varnish 缓存存放的方式,常用的方式有:“-s file,
-T address:port 设定 varnish 的 telnet 管理地址及其端口
-a address:port 表示 varnish 对 http 的监听地址及其端口
回页首
Varnish 配置
VCL 简介
VCL(varnish configuration language)是 varnish 配置语言,其用来定义 varnish 的存取策略。VCL 语法比较简单,跟 C 和 Perl 比较相似。主要有以下几点:
set req.http.X-hit = " hit" "it"; |
VCL backend
声明并初始化一个后端对象,代码如清单 6 所示
backend www { .host = "www.example.com"; .port = "9082"; } |
后端对象的使用,代码如清单 7 所示
if (req.http.host ~ "^(www.)?example.com$") { set req.backend = www; } |
VCL 后端的集合 director
VCL 可以把多个 backends 聚合成一个组,这些组被叫做 director,这样可以增强性能和弹力,当组里一个 backend 挂掉后,可以选择另一个健康的 backend。VCL 有多种 director,不同的 director 采用不同的算法选择 backend,主要有以下几种:
Random director 会根据所设置的权值(weight)来选择 backend,.retries 参数表示尝试找到一个 backend 的最大次数,.weight 参数表示权值
Round-robin director 在选择 backend 时,会采用循环的方式依次选择。
Client director 根据 client.identity 来选择 backend,您可以设置 client.identity 的值为 session cookie 来标识 backend。
backend probes
VCL 可以设置 probe 来检测一个 backend 是否健康,定义一个 backend probes 代码如清单 8 所示:
backend www { .host = "www.example.com"; .port = "9082"; .probe = { .url = "/test.jpg";// 哪个 url 需要 varnish 请求 .timeout = 1 s;// 等待多长时间超时 .interval = 5s// 检查的时间间隔 .window = 5;// 维持 5 个 sliding window 的结果 .threshold = 3;// 至少有三次 window 是成功的,就宣告 backend 健康 } } |
ACL
ACL 可创建一个客户端的访问控制列表,你可以使用 ACL 控制哪些客户端可以访问,哪些客户端禁止访问。定义 ACL 代码如清单 9 所示:
Acl local{ "localhost"; "192.0.2.0"/24; !"192.0.2.23";// 除去该 IP } |
VCL 内置函数
vcl_recv 函数
用于接收和处理请求。当请求到达并成功接收后被调用,通过判断请求的数据来决定如何处理请求。例如如何响应、怎么响应、使用哪个后端服务器等。
此函数一般以如下几个关键字结束。
pass:表示进入 pass 模式,把请求控制权交给 vcl_pass 函数。
pipe:表示进入 pipe 模式,把请求控制权交给 vcl_pipe 函数。
lookup:表示进入 lookup 模式,把请求控制权交给 lookup 指令处理,在缓存中查找被请求的对象,并且根据查找的结果把控制权交给函数 vcl_hit 或函数 vcl_miss。
error code [reason]:表示返回“code”给客户端,并放弃处理该请求。“code”是错误标识,例如 200 和 405 等。“reason”是错误提示信息。
vcl_pipe 函数
此函数在进入 pipe 模式时被调用,用于将请求直接传递至后端主机,在请求和返回的内容没有改变的情况下,将不变的内容返回给客户端,直到这个连接被关闭。
此函数一般以如下几个关键字结束。
error code [reason]。
pipe。
vcl_pass 函数
此函数在进入 pass 模式时被调用,用于将请求直接传递至后端主机。后端主机在应答数据后将应答数据发送给客户端,但不进行任何缓存,在当前连接下每次都返回最新的内容。
此函数一般以如下几个关键字结束。
error code [reason]。
pass。
restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告
vcl_hash
当您想把一个数据添加到 hash 上时,调用此函数。
此函数一般以如下几个关键字结束。
Hash。
vcl_hit 函数
在执行 lookup 指令后,在缓存中找到请求的内容后将自动调用该函数。
此函数一般以如下几个关键字结束。
deliver:表示将找到的内容发送给客户端,并把控制权交给函数 vcl_deliver。
error code [reason] 。
pass。
restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告
vcl_miss 函数
在执行 lookup 指令后,在缓存中没有找到请求的内容时自动调用该方法。此函数可用于判断是否需要从后端服务器获取内容。
此函数一般以如下几个关键字结束。
fetch:表示从后端获取请求的内容,并把控制权交给 vcl_fetch 函数。
error code [reason] 。
pass。
vcl_fetch 函数
在后端主机更新缓存并且获取内容后调用该方法,接着,通过判断获取的内容来决定是将内容放入缓存,还是直接返回给客户端。
此函数一般以如下几个关键字结束。
error code [reason]。
pass。
deliver。
esi。
restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告
vcl_deliver 函数
将在缓存中找到请求的内容发送给客户端前调用此方法。
此函数一般以如下几个关键字结束。
error code [reason]。
deliver。
restart 重新启动流程,增加启动次数,如果重新启动次数高于 max_restarts 发出一个错误警告
vcl_error
出现错误时调用此函数。
此函数一般以如下几个关键字结束。
deliver。
restart。
VCL 处理流程
VCL 处理的流程图如图 1 所示
Varnish 处理 HTTP 请求的过程大致分为如下几个步骤。
VCL 内置公共变量
VCL 内置的公共变量可以用在不同的 VCL 函数中,下面根据使用的不同阶段进行介绍
当请求到达时,可以使用的公共变量表 1 所示
公共变量名 | 含义 |
---|---|
req.backend | 指定对应的后端主机 |
server.ip | 表示服务器 IP |
client.ip | 表示客户端 IP |
req.quest | 只是请求的类型,例如 GET、HEAD 等 |
req.url | 指定请求的地址 |
req.proto | 表示客户端发起请求的 HTTP 协议版本 |
req.http.header | 表示对应请求中的 HTTP 头部信息 |
req.restarts | 表示重启次数,默认最大值为 4 |
Varnish 在向后端主机请求时,可是用的公共变量如表 2 所示
公共变量名 | 含义 |
---|---|
beresp.requset | 指定请求类型,例如 GET、HEAD 等 |
beresp.url | 表示请求地址 |
beresp.proto | 表示客户端发起请求的 HTTP 协议版本 |
beresp.http.header | 表示对应请求中 HTTP 头部信息 |
beresp.ttl | 表示缓存的生存周期,cache 保留时间(s) |
从 cache 或是后端主机获取内容后,可以使用的公共变量如表 3 所示
公共变量名 | 含义 |
---|---|
obj.status | 返回内容的请求状态码,例如 200、302、504 等 |
obj.cacheable | 返回的内容是否可以缓存 |
obj.valid | 是否有效的 HTTP 请求 |
obj.response | 返回内容的请求状态信息 |
obj.proto | 返回内容的 HTTP 版本 |
obj.ttl | 返回内容的生存周期,也就是缓存时间,单位秒 |
obj.lastuse | 返回上一次请求到现在的时间间隔,单位秒 |
对客户端应答时,可以使用的公共变量如表 4 所示
公共变量名称 | 含义 |
---|---|
resp.status | 返回给客户端的 HTTP 代码状态 |
resp.proto | 返回给客户端的 HTTP 协议版本 |
resp.http.header | 返回给客户端的 HTTP 头部消息 |
resp.response | 返回给客户端的 HTTP 头部状态 |
VCL 调试
VCL 为配置文件语言,无法像 c/c++ 那样进行单步调试,当 VCL 运行的效果和预期效果不一样时,很难发现哪出现逻辑错误,这时除了查看代码查找错误外,我们还可以采用内置 C 语言和浏览器查看返回对象中的状态来查找逻辑的错误。
我们可以采用内置 C 语言来打印相应的信息,例如我们可以在相应的地方打印信息,来查看 VCL 流程的执行是否正确。内置 C 语言打印信息代码如清单 10 所示:
C{ #include |
启动 varnish 后,我们可以采用 tail -f /var/log/messages 命令在 /var/log/messages 中查看相应的打印信息。查看的打印信息如图 2 所示:
我们还可以将某些变量的值设置到返回给浏览器的对象上,然后在浏览器中查看该变量的值。设置变量值代码如清单 11 所示:
set beresp.http.X-Cookie-Debug-req-cookie = req.http.Cookie; |
在 chrome 浏览器中查看 beresp.http.X-Cookie-Debug-req-cookie 的值,结果如图 3 所示: