既然varnish需要在多台服务器上缓存数据,就需要varnish映射所有的url到一台单独的主机。
backend webserver {
.host = "127.0.0.1";
.port = "80";
.connect_timeout = 4s;
.first_byte_timeout = 5s;
.between_bytes_timeout = 20s;
}
该块配置用于定义一台varnish默认访问的后端服务器,当varnish需要从后端服务器获取数据时,就会访问自己的80端口。
当然varnish也可以定义多台后端服务器实现负载均衡的目的。
.connect_timeout定义的是等待连接后端的时间
.first_byte_timeout定义的是等待从backend传输过来的第一个字节的时间
.between_bytes_timeout 定义的是两个字节的间隔时间
当然还可以增加一个backend,用于访问本机的8090端口,假设通过该端口提供图片服务。
backend img {
.host = "127.0.0.1";
.port = "8090";
}
当匹配img的url时,需把请求发送到上面定义的backend img,其他的请求发送到backend webserver。
sub vcl_recv {
if (req.url ~ "^/img/") {
set req.backend = img;
} else {
set req.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表示将数据继续保留在缓存中。
acl purge {
"localhost";
"127.0.0.1";
"18.81.12.10";
}
if (req.request == "purge") {
if (!client.ip ~ purge) {
error 405 "not allowed.";
}
return(lookup);
}
这两个规则定义了允许哪些主机通过http来执行purg进行缓存删除。如果不是指定的ip,就会出现http 405错误,提示not allowed错误字样。
if (req.http.host ~ "^(read)?.aaa.com$") {
set req.backend = webserver;
if (req.request != "get" && req.request != "head") {
return(pipe);
}
else {
return(lookup);
}
}
else {
error 404 " cache server";
return(lookup);
}
这段条件判断用于对aaa.com域名进行缓存加速,aaa.com是泛指概念,也就是说所有以aaa.com结尾的域名都进行缓存。而if (req.request != "get" && req.request != "head") 表示"如果请求的类型不是get与head",则返回错误码404。
if (req.url ~ "^/images") {
unset req.http.cookie;
}
这条规则的意思是清除服务器上/images目录下的所有缓存,当这个请求在后端服务器生效时,如果访问的url匹配这个规则,那么头信息中的cookie就会被删除。
if (req.request == "get" && req.url ~ "\\. (png|swf|txt|png|gif|jpg|css|js|htm| html)$") {
unset req.http.cookie;
}
if (req.http.x-forwarded-for) {
set reqreq.http.x-forwarded-for =
req.http.x-forwarded-for ", " client.ip; }
else { set req.http.x-forwarded-for = client.ip; }
因为squid、varnish都会把客户端的ip地址放在http_x_forwarded_for里面传给后端的web服务器,所以后端的web程序都要对其进行调用。
if (req.request != "get" &&
req.request != "head" &&
req.request != "put" &&
req.request != "post" &&
req.request != "trace" &&
req.request != "options" &&
req.request != "delete") {
return (pipe);
}
该if判断表示如果请求的类型不是get、head、put、post、trace、options、delete时,则进入pipe模式。注意这里的"&&"是与的关系。
if (req.request == "get" && req.url ~ "\\. (png|swf|txt|png|gif|jpg|css|js|htm| html)") {
set beresp.ttl = 180s;
}
else {
set beresp.ttl = 30d;
}
return (deliver);
}
该if判断用于对请求类型是get,并且请求的url以png、swf、txt、gif、css、js等结尾时,则进行缓存,缓存时间为180秒。其他缓存为30天。
sub vcl_deliver {
set resp.http.x-hits = obj.hits ;
if (obj.hits > 0) {
set resp.http.x-cache = "hit read.easouu.com";
}
else {
set resp.http.x-cache = "miss read.easou.com";
}
这个模块定义的是添加一个header标识,以判断缓存是否命中。
sub vcl_error {
set obj.http.content-type = "text/html; charset=utf-8";
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>
<address>
<a href="http://read.easou.com/">read.easou.com</a>
</address>
</body>
</html>
"};
return (deliver);
}
最后这个模块定义了访问错误页面时的返回信息。
现在varnish配置基本完成,可以在8080端口上启动varnish,并进行一些基本的测试。
varnish缓存的配置
简单的配置文件内容如下: