varnish 的windows 版本下载地址:
http://sourceforge.net/projects/cygvarnish/files/windows-zip-bundle/
启动:varnish:
C:\varnish\bin>varnishd -a :80 -T :3500 -f c:/varnish/etc/default.vcl -s file,c:/varnish/var/cache,1000M
-a:80表示,让varnish监听在80端口。
-T是为varnish指定一个管理端口;
-f指定所要使用的配置文件;
后面的参数只是让varnish使用文件缓存,大小为1000M,当然,应该根据实际情况指定大小;
启动varnish后,如果我们请求http://地址:端口/,就可以等到200OK状态码,那表示varnish已经在正确滴接受请求。
黄海的配置文件:
backend default {
.host = "192.168.88.177";
.port = "80";
}
#定义可以清空缓存的IP段
acl purge {
"localhost";
"192.168.88.0"/24;
}
sub vcl_recv {
#开启压缩模式,图片格式取消压缩
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|jpeg|flv)" ) {
remove req.http.Accept-Encoding;
remove req.http.Cookie;
} else if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} else if (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
remove req.http.Accept-Encoding;
}
}
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;
}
}
#配置varnish批量刷新缓存
if (req.request == "BAN") {
if (!client.ip ~purge){
error 405 "Not allowed";
}
ban("req.http.host == " +req.http.host+" && req.url ~ "+req.url);
error 200 "Ban added";
}
#把除了以下这些类型请求以外的访问请求全部直接管道发送到后端的服务器
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
#只有GET与HEAD方法才会使用Lookup,使用缓存。
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
#如果请求的是jsp页面直接转发到后端服务器
if (req.url ~ "\.(jsp|action)($|\?)") {
return (pass);
}
return (lookup);
}
sub vcl_pipe {
return (pipe);
}
sub vcl_pass {
return (pass);
}
#使用url+host hash算法查找数据
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
}
# 如果请求为purge 将清除缓存
sub vcl_hit {
#强制刷新后,忽略缓存,直接到后台请求
if(req.http.Cache-Control~"no-cache"||req.http.Cache-Control~"max-age=0"||req.http.Pragma~"no-cache")
{
set obj.ttl=0s;
return (restart);
}
if (req.request == "PURGE") {
set obj.ttl = 0s;
error 200 "Purged";
}
return (deliver);
}
sub vcl_miss {
return (fetch);
}
sub vcl_fetch {
if (beresp.ttl <= 0s ||
beresp.http.Set-Cookie ||
beresp.http.Vary == "*") {
/*
* Mark as "Hit-For-Pass" for the next 2 minutes
*/
set beresp.ttl = 120 s;
return (hit_for_pass);
}
if (beresp.http.Pragma ~"no-cache" ||
beresp.http.Cache-Control ~"no-cache" ||
beresp.http.Cache-Control ~"private") {
return (deliver);
}
#当url中包含servlet时,不进行缓存
if (req.url ~ "^/servlet/")
{
return (hit_for_pass);
}
#当url中包含services时,不进行缓存
if (req.url ~ "^/services/")
{
return (hit_for_pass);
}
if (req.request == "GET" &&
req.url ~ "\.(png|xsl|xml|pdf|ppt|doc|docx|chm|rar|zip|bmp|jpeg|swf|ico|mp3|mp4|rmvb|ogg|mov|avi|wmv|swf|txt|png|gif|jpg|css|js|html|htm)$")
{
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
#设置图片的缓存TTL为一小时
return (deliver);
}
sub vcl_deliver {
#下面是添加一个Header标识,以判断缓存是否命中。
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from dsideal.com";
} else {
set resp.http.X-Cache = "MISS from dsideal.com";
}
return (deliver);
}
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
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>
<p>Varnish cache server</p>
</body>
</html>
"};
return (deliver);
}
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
#
********************************************************************************************************
网上3.0版本的配置说明文字太少了,这篇文章是3.0版本,不错,有时间做个实验。
http://wdj01.blog.51cto.com/1059856/660571
ASP.NET性能优化之反向代理缓存
2011-10-17 08:50 by 陆敏技, 2598 visits, 收藏, 编辑到目前为止,我们讨论了把缓存存放在ASP.NET的输出缓存中(内存和硬盘),以及浏览器缓存中,而大型站点的另一种常用做法是将缓存部署在反向代理服务器上,这类缓存我们通常称之为反向代理缓存,比如Squid和Varnish。这两款软件通常都部署在非WINDOWS平台上,对于Windows平台上的Asp.net来说,其实一样能使用,我们完全可以把反向代理软件部署在LINUX上,然后代理会路由到后台的WINDOWS WEB(IIS)服务器。总之,非WINDOWS的世界很精彩。
当然,无论是squid还是varnish都有Windows的扩展版本。本文为了简便起见,基于varnish的Windows版本来描述的。
varnish的官方站点:https://www.varnish-cache.org/,
varnish的Windows版本:http://www.cygwin.com/,如果要编译过的直接可用的版本,在这里:http://www.software112.com/products/cygwin-varnish-cache.html。
1:将varnish配置为IIS的代理
首先需要为varnish准备配置文件,比如,可以为default.vcl,内容如下:
backend default { .host = "192.168.0.77" ; .port = "80" ; } sub vcl_fetch { remove beresp.http.Set-Cookie; } sub vcl_recv { remove req.http.Cookie; } |
在我们要示范的这个实例中,这3个配置都不能少,如下,
backend default:指定我们的IIS站点的地址和端口;
sub vcl_fetch:这是一个varnish函数,它varnish从后端服务器,也就是IIS中获得数据后被调用;
sub vcl_recv:varnish函数,表示客户端请求杠杠到达反向代理服务器时被调用;
由于varnish默认在碰到http头中含有Cookie相关标识时直接忽略缓存,所以我们需要上面的两个函数针对Cookie做特殊处理。当然,目前这两个函数只是简单而野蛮的删除标识,实际的应用中我们可能需要根据实际情况为它们加上一些判断条件。
2:启动varnish
下面的命令为我启动varnish:
C:\varnish\bin>varnishd -a :8011 -T :8088 -f c:/varnish/etc/default.vcl -s file,c:/varnish/var/cache,100M
-a:8011表示,让varnish监听在8011端口。由于我测试环境下varnish和iis是在同一台机器上,所以IIS已经占用了80,我这里只有使用其它端口。
-T是为varnish指定一个管理端口;
-f指定所要使用的配置文件;
后面的参数只是让varnish使用文件缓存,大小为100M,当然,应该根据实际情况指定大小;
启动varnish后,如果我们请求http://地址:端口/,就可以等到200OK状态码,那表示varnish已经在正确滴接受请求。
3:一个实例
创建asp.net页面,内容如下:
protected void Page_Load( object sender, EventArgs e) { this .Response.AddHeader( "Cache-Control" , "max-age=60" ); this .Response.AddHeader( "Last-Modified" , DateTime.Now.ToString( "U" , DateTimeFormatInfo.InvariantInfo)); DateTime IfModifiedSince; if (DateTime.TryParse( this .Request.Headers.Get( "If-Modified-Since" ), out IfModifiedSince)) { if ((DateTime.Now - IfModifiedSince.AddHours(8)).Seconds < 60) { Response.Status = "304 Not Modified" ; Response.StatusCode = 304; return ; } } string conn = "Data Source=192.168.0.77;Initial Catalog=luminjidb;User Id=sa;Password=sa;" ; using (DataSet ds = Common.SqlHelper.ExecuteDataset(conn, CommandType.Text, "select top 1* from NameTb a, DepTb b where a.DepID = b.ID ORDER BY NEWID()" )) { var result = ds.Tables[0].Rows[0][ "name" ].ToString(); Response.Write(result); } } |
对该页面进行压力测试,100个用户,1000个请求,得到的结果如下:
如果没有缓存,则结果如下:
可以看到吞吐率有非常大的提升。
4:监控varnish
可以使用varnishstat命令,对varnish进行监控,在上面的压力测试中,如果我们使用监控,得到的结果如下:
在本例中,我们可以看到共请求了1000次,其中999次命中缓存,那是因为第一次显然肯定是要从IIS中拿输出滴。
5:管理varnish
可以通过多种途径来进行varnish的管理,包括更改配置、停止服务、启动服务、清理缓存等。可以通过varnishadm命令进行管理,如果你是在远程的话,可以使用telnet来进行管理:
telnet 192.168.0.77 8088
其中8088就是我们刚在启动varnish的时候指定的管理端口。连接上之后,stop停止服务、start启动服务,可以敲入help查看所有命令。下面的命令,清除所有缓存:
purge.url *$
6:谨慎引入varnish后带来的缓存变化
引入varnish后,可以发现使用强制刷新(ctrl+R5)后,动态行为发生了改变,即客户端浏览器会去VARNISH上请求数据,但是此时的缓存中已经存在静态的缓存内容,varnish会首先根据请求的HTTP头去和这个缓存内容判断得出需要是否更新,即由于缓存内容的存在,请求不会去IIS上进行缓存协商。这个时候,缓存中的静态内容会直接返回给客户端浏览器,这样一来的话,我们在Page_Load中的代码就根本不会执行,因为它是在IIS中的。
要避免这种情况的发生,我们必须更改VARNISH配置文件,让VARNISH碰到强制更新的时候,忽略缓存,直接去IIS上请求,为配置文件增加如下函数:
sub vcl_hit { if (req.http.Cache-Control~ "no-cache" ||req.http.Cache-Control~ "max-age=0" ||req.http.Pragma~ "no-cache" ){ set obj.ttl=0s; return (restart); } return (deliver); } |
经过上面的修改后,再次使用强制更新varnish将会忽略缓存,到IIS上去拿正文。
参考:
https://www.varnish-cache.org/docs/trunk/reference/varnishlog.html
https://www.varnish-cache.org/trac/wiki/Introduction#TheVarnishConfigurationLanguage
http://www.docunext.com/wiki/Varnish
http://cd34.com/blog/infrastructure/no-esi-processing-first-char-not/
本系列之前篇: