1、varnish简介
Varnish 是一款高性能且开源的反向代理服务器(Reverse Proxy Server),挪威最大的线上报纸 Verdens Gang 使用3台Varnish代替了原本的12台Squid, 性能比以前更好。Varnish 的作者 Poul-Henning Kamp 是 FreeBSD 核心的开发人员之一,他认为现在的电脑比起1975年已经复杂许多。在那个时代,存储媒介只有两种:记忆体与硬盘。但现在电脑系统的记忆体除了主记忆体外,还包括了CPU内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此squid cache自行处理物件替换的架构不可能得知这些情況而做到最佳化,但作业系统可以得知这些情況,所以这部份的工作有关交给作业系统处理,这就是 Varnish Cache 的设计架构。
一般來说,使用Varnish代替Squid的理由有三点:
1.1 Varnish采用了“Visual Page Cache”技术,在记忆体的利用上,Varnish 比 Squid 更具有优势,它避免了Squid频繁在记忆体、硬盘中交换文件,性能比 Squid 还高。
1.2 Varnish的稳定性高,进行相同工作的Squid服务器发生故障的几率似乎比Varnish高。
1.3 通过Varnish管理端口,可以使用正则表达式、批量地清除部分缓存,这一点是Squid不能具备的。
2、linux 系统安裝 Varnish 的过程:
2.1 首先建立www用戶和组,以及Varnish缓存存放目录:
2.2 建立 Varnish 日志目录:
2.3 代码快速获取地址:
2.4 源代码安装Varnish
tar zxvf pcre-7.9.tar.gz
cd pcre-7.9/
./configure --prefix=/usr/local/webserver/pcre-7.9/
make && make install
cd ../
设置 PKG_CONFIG_PATH
export PKG_CONFIG_PATH=/usr/local/pcre-7.9/lib/pkgconfig
tar -zxvf varnish-2.1.tar.gz
cd varnish-2.1
./configure --prefix=/usr/local/varnish-2.1/ --enable-dependency-tracking --enable-debugging-symbols --enable-developer-warnings
make
make install
注:如果你的gcc版本是4.2.0或更高的版本,可以加上–enable-extra-warnings编译参数,在出错时,得到附加的警告信息。
我这里是用源码包安装的,如果你是redhat或centos可以用rpm包来安装
3、编辑配置文件 /usr/local/varnish-2.1/etc/varnish/default.vcl:
这里我对这段配置文件说明一下:
(1) Varnish通过反向代理访问192.168.1.104和192.168.1.105,端口为80的Web服务器;
(2) Varnish对hiphp.com或者hiphpimg.com域名进行缓存;
(3) Varnish对以.asp和.cgi已经带有?的URL直接从源服务器取;
(4) Varnish对fetch里边符合正则表达式的连接进行指定时间的缓存。
配置范例:
backend web4 {
.host = "192.168.1.104";
.port = "80";
.probe = {
.timeout = 50 ms;
.interval = 5s;
.window = 10;
.threshold = 8;
.request =
"GET /index.php HTTP/1.1"
"Host: 192.168.1.104"
"Connection: close"
"Accept-Encoding: foo/bar" ;
}
}
backend web5 {
.host = "192.168.1.105";
.port = "80";
.probe = {
.timeout = 50 ms;
.interval = 5s;
.window = 10;
.threshold = 8;
.request =
"GET /index.php HTTP/1.1"
"Host: 192.168.1.105"
"Connection: close"
"Accept-Encoding: foo/bar" ;
}
}
director web random {
{ .backend = web4; .weight = 1; }
{ .backend = web5; .weight = 1; }
}
sub vcl_recv {
set req.grace = 30s;
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;
}
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);
}
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
# if (req.http.Authorization || req.http.Cookie) {
# /* Not cacheable by default */
# return (pass);
# }
# if (req.http.user-agent ~ "(.*)(Nokia|Sony|Ericsson|Motorola|Samsung|Lg|Sie-|Philips|Panasonic|Alcatel|Lenovo|Cldc|Midp|Wap|Mobile)(.*)")
# {
# error 750 "ganji.cn";
# }
if (req.http.host ~ "^(.*).hiphp.com" || req.http.host ~ "^(.*).hiphpimg.com") {
set req.backend = web;
}
if (req.url ~ ".(asp|cgi)($|?)") {
return (pass);
} else {
return (lookup);
}
}
#sub vcl_error {
# if (obj.status == 750)
# {
# if (req.http.host ~ "^(.*).ganji.com")
# {
# set obj.http.Location = "http://"regsub(req.http.host,"com","cn");
# }
# }
# set obj.status = 302;
# return (deliver);
#}
sub vcl_pipe {
# Note that only the first request to the backend will have
# X-Forwarded-For set. If you use X-Forwarded-For and want to
# have it set for all requests, make sure to have:
# set req.http.connection = "close";
# here. It is not set by default as it might break some broken web
# applications, like IIS with NTLM authentication.
return (pipe);
}
sub vcl_pass {
return (pass);
}
sub vcl_hash {
set req.hash += req.url;
if (req.http.host) {
set req.hash += req.http.host;
} else {
set req.hash += server.ip;
}
return (hash);
}
sub vcl_hit {
if (!obj.cacheable) {
return (pass);
}
return (deliver);
}
sub vcl_miss {
return (fetch);
}
sub vcl_fetch {
set req.grace = 30s;
if (!beresp.cacheable) {
return (pass);
}
if (beresp.http.Set-Cookie) {
return (pass);
}
#Not to cache
if (req.url ~ "^/vip/") {
return (pass);
}
#To cache
if (req.request == "GET" && req.url ~ "/[0-9]{4}.htm$") {
set beresp.ttl = 300s;
}
if (req.request == "GET" && req.url ~ "^/[a-z]+d?/$") {
set beresp.ttl = 300s;
}
if (req.request == "GET" && req.url ~ "^/fang(.*)$") {
set beresp.ttl = 300s;
}
if (req.request == "GET" && req.url ~ "^/piao(.*)$") {
set beresp.ttl = 20s;
}
if (req.request == "GET" && req.url ~ ".(png|swf|txt|png|gif|jpg|css|js|htm)$") {
set beresp.ttl = 3600s;
}
if (req.request == "GET" && req.url ~ "/([0-9]+)_([0-9]*).htm$") {
set beresp.ttl = 3104000s;
}
return (deliver);
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from bj-185.cache.ganji.com";
} else {
set resp.http.X-Cache = "MISS from bj-185.cache.ganji.com";
}
return (deliver);
}
4、用适当权限启动 Varnish
5、配置开机自动启动 Varnish
编辑启动执行脚本/etc/rc.local並将上面內容贴到最下方,也可以写成一个启动脚本varnish.sh
6、启动 varnishncsa,用来将Varnish访问日志写入日志文件:
7、Varnish 优化
7.1 优化Linux核心参数
编辑/etc/sysctl.conf 在底部增加以下内容:
net.ipv4.tcp_keepalive_time = 300
#表示当Keepalive起用的时候,TCP发送keepalive消息的频繁度。预设值是2小时,这里我改为5分钟。
net.ipv4.tcp_tw_reuse = 1
#表示开启重用。允許將TIME-WAIT sockets重新用於新的TCP連接,預設为0,表示开关,我將它开啟。
net.ipv4.tcp_tw_recycle = 1
#表示开启TCP連接中TIME-WAIT sockets的快速回收,预设为0,表示开关,我将它开启。
net.ipv4.tcp_max_tw_buckets = 5000
#表示系統同时保持TIME_WAIT套接字的最大属性,如果超过这个数字,TIME_WAIT套接字將立刻被清除並印出警告訊息。预设是180000,改为5000。
之后记得执行 /sbin/sysctl -p 使配置生效。
以下配置是官网提供:(官网上说,此配置可以支持4000-8000 req/s的压力.)
net.ipv4.ip_local_port_range = 1024 65536
#表示用來向外连接的端口范围。预设情况下很小:32768到61000,我将它改为1024到65536。
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
net.ipv4.tcp_fin_timeout = 3
#表示如果套接字由本端要求开放,这个参数决定了它保持在FIN-WAIT-2状态的时间。
net.core.netdev_max_backlog = 30000。
net.ipv4.tcp_no_metrics_save=1
net.core.somaxconn = 262144
net.ipv4.tcp_syncookies = 0
#表示开启SYN Cookies。当出现SYN等待对列溢出时,启用cookies來处理,可防范少量SYN攻击,预设为0。
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
#表示SYN队列的长度,预设为1024,加大队列长度为262144,可容纳更多等待连接的网路连接数。
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
7.2 系统环境优化
7.3 VCL优化
7.4 参数优化.(“telnet localhost 5000″后,输入”param.show”可以看到所有系统运行中的参数.输入”param.set thread_pools 8″可以调整参数.)
thread_pools 8 [pools]
thread_pool_max 2000 [threads]
thread_pool_min 100 [threads]
thread_pool_timeout 10 [seconds]
#这四个参数要一起看.
#thread_pools是系统sess进入处理的pools.理想的情况下是一个cpu一个pool,如果pools过多会消耗cpu时间和mem.但是,pools多一点,处理并发的能力会更强.
#thread_pool_min是每个pools的最小threads数.当pools侦测到可处理sess后,就分配给所属的空余threads处理.
#thread_pool_max是所有pools所属的threads总和数的上限值.这个值不要设置的太高,一般是系统期望峰值的90%.太高了会发生"pile-ups",不知道怎么翻译,是不是"拥挤"?
#thread_pool_timeout是thread的过期时间.当threads数大于thread_pool_min的时候,thread的空闲超过thread_pool_timeout时间,thread就被释放.
listen_depth 1024 [connections] #tcp链接队列size.默认是512,适当调大一点,处理并发能力增强.
lru_interval 20 [seconds]
#优雅时间参数(不知道是不是应该这么翻译),意思就是,如果一个object,在内存中超过了这个时间还没有被重用,则把这个对象移动到 LRU(Least Recently Used)队列中.一种普遍的cache算法.个人理解,提高这个时间,会减少object在内存中的copy,以提高运行效率.
8、接下來看看如何管理Varnish:
8.1 查看 Varnish 服务器连接数与命中率:
8.2 通过 Varnish 管理端口進行管理(用 –help查看可用的指令)
8.3 通过Varnish管理端口,使用正则表达式批量清除缓存:
(1) 例如:清除类似http://www.example.com/a/abc.html的url地址:
(2) 例如:清除类似http://www.example.com/tech的URL地址:
(3) 例如:清除所有缓存:
8.4 下面是一个每天0点执行,按天切割Varnish日志,生成一个压缩文档,同时删除上个月旧日志的腳本(/usr/local/shell/cutlog.sh):
#!/bin/sh
# This file run at 00:00
date=$(date -d "yesterday" +"%Y-%m-%d")
pkill -9 varnishncsa
mv /data/varnish/logs/varnish.log /data/varnish/logs/${date}.log
/usr/local/varnish-2.1/bin/varnishncsa -a -w /data/varnish/logs/varnish.log &
gzip -c /data/varnish/logs/${date}.log > /data/varnish/logs/${date}.log.gz
rm -f /data/varnish/logs/${date}.log
rm -f /data/varnish/logs/$(date -d "-1 month" +"%Y-%m*").log.gz
设定在每天早上00:00定时执行:
sudo /usr/bin/crontab -e
添加以下內容
0 0 * * * /usr/local/shell/cutlog.sh
8.5 如果你要确定varnish是否有正确执行,你可以用netstat -atp看有沒有一个正在监听的3500端口,或者用pa aux | grep varnishd看这个程序是否有在运行。
8.6 Varnish监控程序使用