一、Varnish简介:
Varnish是一款高性能的开源HTTP加速器,varnish项目是2006年发布的第一个版本,现在很多门户网站已经部署了varnish,并且反应都很好,甚至反应比squid还稳定,且效率更高,资源占用更少,在功能上,它可以作为反向代理服务器和缓存服务器使用,不过它的反向代理功能不如haproxy或者nginx性能强大,所以它的应用多数都在缓存服务器的场景下。
二、Varnish的核心引擎以及常用变量类型:
Varnish有9个核心引擎,用于处理用户请求以及后端服务器响应的报文,当然处理的报文更多的目的是判断是否需要缓存以及与缓存相关的特性或者是要处理的执行动作。在很多时候,我们需要从连贯的角度考虑数据流经这几个引擎上的可能,需要考虑数据报文经由这些引擎时可能执行的流程,这有助于我们完整的编写其配置文件,也有助于我们更好的理解Varnish内部的数据处理机制。
Varnish内部的核心引擎:
vcl_recv、vcl_pipe、vcl_pass、vcl_hash、vcl_hit、vcl_miss、vcl_fetch、vcl_deliver、vcl_error
Varnish中可用的内置变量:
请求到达时可用的内置变量
req.url、req.request、req.http.header、req.restarts、server.ip、server.port、server.hostname、client.ip、req.backend
向后端主机请求时可用的内置变量
bereq.url、bereq.request、bereq.http.header、bereq.connect_timeout、bereq.proto
从后端主机获取到相应的object时可用的内置变量
beresp.response、beresp.status、beresp.http.header、beresp.backend.name、beresp.backend.ip、beresp.backend.port、beresp.ttl
二、Varnish的应用:
1、Varnish在作为缓存服务器工作的同时,它的另外一个角色与Haproxy相同,也就是要作为反向代理使用,而请求后端服务器数据时,请求者的身份是Varnish而不再是客户端,也意味着在上游服务器的日志记录中记录的请求者的信息是代理服务器的IP地址,这通常不是我们需要的,通常需要记录的是真实的客户端IP地址,如果要在后端服务器端记录该地址,使用的方式如下:
首先需要定义后端的服务器信息,Varnish的配置文件如果是基于RPM包安装的方式安装的,为/etc/varnish目录下的default.vcl,如果后端主机为172.16.103.2,那么相应在配置文件中定义内容为:
backend default { .host = "172.16.103.2"; .port = "80"; }
注意:在Varnish的配置文件中默认就是将客户端的真实IP地址发送给服务器端,所以我们需要启用Varnish的默认配置文件中vcl.req段的配置,然后修改的是后端服务器记录日志的格式就可以了。
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; } } return (lookup); }
修改后端服务器的httpd服务的配置文件保存日志的格式为:
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" combined
这样在客户端请求数据报文发给前端的Varnish主机时,如果没有缓存,会将请求发往后端服务器,并记录真实的客户端IP地址,例如:
172.16.103.111 - - [26/Sep/2014:23:54:26 +0800] "GET /favicon.ico HTTP/1.1" 404 287 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36" -
2、当有些请求的资源不需要缓存时,可以在Varnish的配置文件中的vcl_recv段中使用如下的方式定义:
if (req.url ~ "^/test.html$") { return (pass);
语句的含义是使用正则表达式来匹配以/test.html开头的uri,如果用户请求的是这种类型的资源,就直接将请求发往后端主机,而不使用缓存,使用这种方式我们也可以测试客户端的请求是否可以直接发往后端的服务器。测试效果如下:
3、当某些缓存资源需要清理时,我们需要执行PURGE操作,定义的方式如下:
这个操作可能出现的情况比较多,首先,因为Varnish缓存的数据在实际的应用场景中会非常重要,不能随意允许其他人连入直接删除缓存的操作,所以要执行这种操作时,需要判断用户的身份,在Varnish的配置文件中,可以使用acl列表定义允许使用PURGE的用户列表,然后在各个可能出现PURGE操作的执行引擎位置定义该操作的执行效果。示例如下:
acl purgers { "127.0.0.1"; "172.16.103.0"/24; }
sub vcl_recv { if (req.request == "PURGE") { if (client.ip !~ purgers) { error 405 "Method not allowed."; } return(lookup); } return (lookup); }
sub vcl_pass { if (req.request == "PURGE") { error 502 "PURGE on a passwd object"; } return (pass); }
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); }
这样定义好之后,每当用户发起PURGE请求时,数据报文在到达vcl.recv时会先判断用户的身份,如果用户的身份与定义的acl中的规则匹配,则允许用户执行后续的操作,后续的操作中如果用户删除的缓存条目存在,则显示200返回码,并显示Purged,如果删除的缓存条目不存在,则显示错误404,并提示要删除的条目不在缓存中,当用户的数据报文如果经过vcl_pass时,由于是发往后端主机的,所以不可能有删除缓存的可能性,所以会提示502错误。
具体删除缓存条目时的删除示例:
[[email protected] html]# curl -X PURGE http://172.16.103.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>200 Purged</title> </head> <body> <h1>Error 200 Purged</h1> <p>Purged</p> <h3>Guru Meditation:</h3> <p>XID: 1703226672</p> <hr> <p>Varnish cache server</p> </body> </html>
4、Varnish可以实现对后端服务器提供健康检测的功能,定义的方式如下:
backend default { .host = "172.16.103.2"; .port = "80"; .probe = { .url = "/index.html"; .interval = 2s; .window = 8; .threshold = 2; } }
具体查看时可以使用telnet连接到Varnish使用其中的backend.list命令来查看后端服务器的健康状况:
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 varnish> backend.list 200 Backend name Refs Admin Probe default(172.16.103.2,,80) 1 probe Healthy (no probe) web1(172.16.103.2,,80) 1 probe Healthy 8/8
5、当Varnish作为反向代理时,其后端可以有多个服务器提供服务,在Varnish配置文件中可以定义多个后端的backend server同时还可以将多个服务器定义为一个组,使用director关键字来定义,在处理引擎中需要用到各director时再调用即可,在定义director时,由于Varnish有负载均衡的效果,所以调度的时候有相应的算法,算法有两种,分别的random和round-robin,配置示例:
backend web1 { .host = "172.16.103.2"; .port = "80"; .probe = { .url = "/index.html"; .interval = 2s; .window = 8; .threshold = 2; } } backend web2 { .host = "172.16.103.3"; .port = "80"; .probe = { .url = "/index.html"; .interval = 2s; .window = 8; .threshold = 2; } } acl purgers { "127.0.0.1"; "172.16.103.0"/24; } director webservers round-robin { { .backend = web1; } { .backend = web2; } }
定义好各后端的服务器及director之后,就可以在需要调用director的处理引擎段中调用director了,比如在vcl.recv段中定义:
sub vcl_recv { set req.backend = webservers;
这样当数据请求报文到达Varnish主机时,会自动将数据请求报文依据定义的算法调度至后端的各服务器进行响应,同时,如果响应的结果可以缓存,那么会有一份结果保存在Varnish中,之后再次请求时,会直接由Varnish响应之后的用户请求。