wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-libs-3.0.4-1.el6.x86_64.rpm wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-3.0.4-1.el6.x86_64.rpm wget http://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/varnish-docs-3.0.4-1.el6.x86_64.rpm yum localinstall *.rpm
varnish的安装和配置路径
/etc/varnish/default.vcl #默认配置文件存文件 /etc/sysconfig/varnish #服务启动参数脚本 /etc/init.d/varnish #服务控制脚本
可以通过调整 /etc/sysconfig/varnish 配置文件中的参数来调整启动参数,设置线程池、缓存到内存还是文件等。当然如果你乐意也可以在varnishd后面带上启动参数手工启动服务和管理。
现在能通过服务的方式启动 varnish了:service varnish start (stop/restart)将varnish设为开机自启动:
chkconfig varnish on
yum install ncurses-devel.x86_64
此步可选。
如果你在编译varnish 后bin目录中没有发现 varnishstat、varnishtop、varnishhist这三个程序的话,就是因为编译前没有安装与操作系统位数对应的 ncurses-devel。这些工具非常好用,因此建议先安装这个依赖包。cd pcre-8.12 ./configure --prefix=/usr/local/ make&&make install
wget http://repo.varnish-cache.org/source/varnish-3.0.4.tar.gz cd /root tar -zxvf varnish-3.0.4.tar.gz cd varnish-3.0.4 export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/usr/local/varnish make && make install
import std;在需要输出日志的地方,使用 std.log 即可:
std.log("LOG_DEBUG: URL=" + req.url);这样的话,就可以通过日志了解varnish的工作流程,很方便的优化啦,效率何止提高十倍!
sub vcl_miss { td.log("url miss!!! url=" + req.url); return (fetch); }启动varnish 后,通过 varnishlog工具跟踪打印出的日志
varnishlog -I LOG
backend web1 { .host = "172.16.2.31"; .port = "80"; .probe = { .url = "/"; .interval = 10s; .timeout = 2s; .window = 3; .threshold = 3; } } backend web2 { .host = "172.16.2.32"; .port = "80"; .probe = { .url = "/"; .interval = 10s; .timeout = 2s; .window = 3; .threshold = 3; } } # 定义负载均衡组 director webgroup random { { .backend = web1; .weight = 1; } { .backend = web2; .weight = 1; } }
其中,在backend 中添加 probe 选项,将可以对后端节点进行健康检查。如果后端节点无法访问,将会自动摘除掉该节点,直到这个节点恢复。
需要注意window 和threshold 两个参数。当有后端服务器不可达时,varnish会时不时的报503错误。网上查出的资料都是改线程组什么的,经测试完全无效。后来发现,只要将 window 和threshold 两个参数的值设成一样的,503现象就再没有发生了。sub vcl_fetch { if (beresp.status == 500) { set beresp.saintmode = 10s; return (restart); } set beresp.grace = 5m; }
import std; backend web1 { .host = "172.16.2.31"; .port = "80"; .probe = { .url = "/"; .interval = 10s; .timeout = 2s; .window = 3; .threshold = 3; } } backend web2 { .host = "172.16.2.32"; .port = "80"; .probe = { .url = "/"; .interval = 10s; .timeout = 2s; .window = 3; .threshold = 3; } } # 定义负载均衡组 director webgroup random { { .backend = web1; .weight = 1; } { .backend = web2; .weight = 1; } } # 允许刷新缓存的ip acl purgeAllow { "localhost"; "172.16.2.5"; } sub vcl_recv { # 刷新缓存设置 if (req.request == "PURGE") { #判断是否允许ip if (!client.ip ~ purgeAllow) { error 405 "Not allowed."; } #去缓存中查找 return (lookup); } std.log("LOG_DEBUG: URL=" + req.url); set req.backend = webgroup; 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 请求 if (req.request != "GET" && req.request != "HEAD") { std.log("LOG_DEBUG: req.request not get! " + req.request ); return(pass); } # http 认证的页面也 pass if (req.http.Authorization) { std.log("LOG_DEBUG: req is authorization !"); return (pass); } if (req.http.Cache-Control ~ "no-cache") { std.log("LOG_DEBUG: req is no-cache"); return (pass); } # 忽略admin、verify、servlet目录,以.jsp和.do结尾以及带有?的URL,直接从后端服务器读取内容 if (req.url ~ "^/admin" || req.url ~ "^/verify/" || req.url ~ "^/servlet/" || req.url ~ "\.(jsp|php|do)($|\?)") { std.log("url is admin or servlet or jsp|php|do, pass."); return (pass); } # 只缓存指定扩展名的请求, 并去除 cookie if (req.url ~ "^/[^?]+\.(jpeg|jpg|png|gif|bmp|tif|tiff|ico|wmf|js|css|ejs|swf|txt|zip|exe|html|htm)(\?.*|)$") { std.log("*** url is jpeg|jpg|png|gif|ico|js|css|txt|zip|exe|html|htm set cached! ***"); unset req.http.cookie; # 规范请求头,Accept-Encoding 只保留必要的内容 if (req.http.Accept-Encoding) { if (req.url ~ "\.(jpg|png|gif|jpeg)(\?.*|)$") { remove req.http.Accept-Encoding; } elsif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { remove req.http.Accept-Encoding; } } return(lookup); } else { std.log("url is not cached!"); return (pass); } } sub vcl_hit { if (req.request == "PURGE") { set obj.ttl = 0s; error 200 "Purged."; } return (deliver); } sub vcl_miss { std.log("################# cache miss ################### url=" + req.url); if (req.request == "PURGE") { purge; error 200 "Purged."; } } sub vcl_fetch { # 如果后端服务器返回错误,则进入 saintmode if (beresp.status == 500 || beresp.status == 501 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) { std.log("beresp.status error!!! beresp.status=" + beresp.status); set req.http.host = "status"; set beresp.saintmode = 20s; return (restart); } # 如果后端静止缓存, 则跳过 if (beresp.http.Pragma ~ "no-cache" || beresp.http.Cache-Control ~ "no-cache" || beresp.http.Cache-Control ~ "private") { std.log("not allow cached! beresp.http.Cache-Control=" + beresp.http.Cache-Control); return (hit_for_pass); } 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 (req.request == "GET" && req.url ~ "\.(css|js|ejs|html|htm)$") { std.log("gzip is enable."); set beresp.do_gzip = true; set beresp.ttl = 20s; } if (req.request == "GET" && req.url ~ "^/[^?]+\.(jpeg|jpg|png|gif|bmp|tif|tiff|ico|wmf|js|css|ejs|swf|txt|zip|exe)(\?.*|)$") { std.log("url css|js|gif|jpg|jpeg|bmp|png|tiff|tif|ico|swf|exe|zip|bmp|wmf is cache 5m!"); set beresp.ttl = 5m; } elseif (req.request == "GET" && req.url ~ "\.(html|htm)$") { set beresp.ttl = 30s; } else { return (hit_for_pass); } # 如果后端不健康,则先返回缓存数据1分钟 if (!req.backend.healthy) { std.log("eq.backend not healthy! req.grace = 1m"); set req.grace = 1m; } else { set req.grace = 30s; } return (deliver); } # 发送给客户端 sub vcl_deliver { if ( obj.hits > 0 ) { set resp.http.X-Cache = "has cache"; } else { #set resp.http.X-Cache = "no cache"; } return (deliver); }