打建性能比squid高很多的varnish服务器

https://www.varnish-cache.org/

最新安装:https://www.varnish-cache.org/docs/3.0/installation/install.html#source-or-packages

varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (http://www.vg.no) 使用3台Varnish代替了原来的12台squid,

性能比以前更好。
varnish的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多。在1975年时,储存媒介只有两

种:内存与硬盘。但现在计算机系统的内存除了主存外,还包括了cpu内的L1、L2,甚至有L3快取。硬盘上也有自己的快取装置,因此squid

cache自行处理物件替换的架构不可能得知这些情况而做到最佳化,但操作系统可以得知这些情况,所以这部份的工作应该交给操作系统处理,

这就是 Varnish cache设计架构。

1.下载源码包编译安装:

cd /usr/local/src && wget http://nchc.dl.sourceforge.net/sourceforge/varnish/varnish-1.1.1.tar.gz
tar zxvf /usr/local/src/varnish-1.1.1.tar.gz
cd /usr/local/src/varnish-1.1.1
./autogen.sh
./configure –enable-debugging-symbols –enable-developer-warnings –enable-dependency-tracking
注:如果你的gcc版本是4.2.0或更高的版本,可以加上–enable-extra-warnings编译参数,在出错时,得到附加的警告信息。
我这里是用源码包安装的,如果你是redhat或centos可以用rpm包来安装(rpm下载位置:http: //sourceforge.net/project/showfiles.php?

group_id=155816&package_id=173643&release_id=533569).

2. 建立cache目录:
mkdir -p /cache/varnish/V && chown -R nobody:nobody /cache

3.编写启动文件:

cd /usr/local/varnish/sbin
vi start.sh
内容如下:
#!/bin/sh
# file: go.sh
date -u
/usr/local/varnish/sbin/varnishd \
-a 10.0.0.129:80 \
-s file,/cache/varnish/V,1024m \
-f /usr/local/varnish/sbin/vg.vcl.default \
-p thread_pool_max=1500 \
-p thread_pools=5 \
-p listen_depth=512 \
-p client_http11=on \

-T 0.0.0.0:8082
注:-a 是指定后端服务器的ip或hostname,就象squid做revese proxy时的originserver.
不过这个也可以在vcl里面写。
-f 是指定所用的vcl的文件。
-s 指定cache目录的存储类型,文件位置和大小。
-p 是指定varnish的启动的一些启动参数,可以根据自己的机器配置来优化varnish的性能。

-T address:port # telnet管理地址及其端口
其他参数已经参数的具体含义可以用varnishd –help 来查看。

4.编写vcl:
我的vcl如下:

backend default {
set backend.host = “127.0.0.1″;
set backend.port = “http”;
}

#我用的是一台机器做测试,使用的backend用的是127.0.0.1:80.如果varnish机器和后台的机器分开的。
写上对应的机器的ip或hostname就可以了。

sub vcl_recv {

if (req.request != “GET” && req.request != “HEAD”) {
pipe;
}

if (req.http.Expect) {
pipe;
}

if (req.http.Authenticate || req.http.Cookie) {
pass;
}

if (req.request == “GET” && req.url ~ “\.(gif|jpg|swf|css|js)$”) {
lookup;
}
lookup;
}

sub vcl_pipe {
pipe;
}

sub vcl_pass {
pass;
}

sub vcl_hash {
hash;
}

sub vcl_hit {
if (!obj.cacheable) {
pass;
}
deliver;
}

sub vcl_timeout {
discard;
}

sub vcl_discard {
discard;
}

如果是多个站点在不同的originserver时,可以使用下面配置:

backend www {
set backend.host = “www.jackbillow.com”;
set backend.port = “80″;
}

backend images {
set backend.host = “images.jackbillow.com”;
set backend.port = “80″;
}

sub vcl_recv {
if (req.http.host ~ “^(www.)?jackbillow.com$”) {
set req.http.host = “www.jackbillow.com”;
set req.backend = www;
} elsif (req.http.host ~ “^images.jackbillow.com$”) {
set req.backend = images;
} else {
error 404 “Unknown virtual host”;
}

5.启动varnish:

/usr/local/varnish/sbin/start.sh

Mon Sep 3 03:13:19 UTC 2007
file /cache/varnish/V/varnish.tEKXXx (unlinked) size 1073741824 bytes (262144 fs-blocks, 262144 pages)
Using old SHMFILE

ps waux | grep varnish
root 16254 0.0 0.0 11200 708 ? Ss 10:43 0:00 /usr/local/varnish/sbin/varnishd -a 10.0.0.129:80 -s /varnish/V,1024m

-f /usr/local/varnish/sbin/vg.vcl.default -p thread_pool_max 1500 -p thread_pools 5 -p listen_depth 512 -p client_http11 on
nobody 16255 0.0 0.1 1152552 1808 ? Sl 10:43 0:00 /usr/local/varnish/sbin/varnishd -a 10.0.0.129:80 -s

file,/cache/varnish/V,1024m -f /usr/local/varnish/sbin/vg.vcl.default -p thread_pool_max 1500 -p thread_pools 5 -p

listen_depth 512 -p client_http11 on

看到上面信息说明varnish正确启动,恭喜你,你已经配置成功了。:)

 

-----------------------------------------------------------------------------------------

varnish cache 配置过程

和Squid相比Varnish更适合在大内存的server上使用。

软件:varnish-1.1.2.tar.gz

安装过程
#/usr/sbin/groupadd www -g 48
#/usr/sbin/useradd -u 48 -g www www
#mkdir -p /var/vcache
#chmod +w /var/vcache
#chown -R www:www /var/vcache
#mkdir -p /var/log/varnish
#chmod +w /var/log/varnish
#chown -R www:www /var/log/varnish
#cd /data/software
#tar zxvf varnish-1.1.2.tar.gz
#cd varnish-1.1.2
#./configure --prefix=/usr/local/varnish
#make && make install

编辑Varnish配置文件
#vi /usr/local/varnish/vcl.conf

backend webserver {
       set backend.host = "10.10.10.8";
       set backend.port = "80";
}

acl purge {
       "localhost";
       "127.0.0.1";
       "10.10.10.0"/24;
}

sub vcl_recv {
        remove req.http.X-Forwarded-For;
        set    req.http.X-Forwarded-For = client.ip;
        if (req.request == "PURGE") {
               if (!client.ip ~ purge) {
                       error 405 "Not allowed.";
               }
               lookup;
       }

       if (req.http.host ~ "(a|b|c).test.com") {
               set req.backend = webserver;
              if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") {
                       lookup;
        }
               else {
                       pass;
               }
       }

       else {
               error 404 "Test Cache Server";
               pipe;
       }
}

sub vcl_hash {
    set req.hash += req.url;
    if (req.http.host) {
        set req.hash += req.http.host;
    } else {
        set req.hash += server.ip;
    }
    hash;
}

sub vcl_pipe {
        set req.http.connection = "close";
        #pipe;
}

sub vcl_hit {
        if (!obj.cacheable) {
                pass;
        }
       if (req.request == "PURGE") {
               set obj.ttl = 0s;
               error 200 "Purged.";
       }
        deliver;
}

sub vcl_miss {
       if (req.request == "PURGE") {
               error 404 "Not in cache.";
       }
}

sub vcl_fetch {
               set obj.ttl = 180s;
               #set    obj.http.X-Varnish-IP = server.ip;
               set    obj.http.Varnish = "Tested by Kevin";
}

启动Varnish
#/usr/local/varnish/sbin/varnishd -n /var/vcache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:80 -s file,/var/vcache/varnish_cache.data,4G -u apache -w 30000,51200,10 -T 127.0.0.1:3500 -p client_http11=on -p thread_pools=4

启动日志记录
#/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/log/varnish/varnish.log &

补充几条相关命令
查看Varnish状态
/usr/local/varnish/bin/varnishstat -n /var/vcache/

查看访问最多的Referer
/usr/local/varnish/bin/varnishtop -n /var/vcache/ -i rxheader -I Referer

查看访问最多的URL
/usr/local/varnish/bin/varnishtop -n /var/vcache/ -i rxurl

等了N久还不见新的版本出来,于是忍不住先学习一下,主要是看man page。

基本明白,但英语还是太差,理解能力也有限,有些细微之处不很明白,比如pass和pipe的区别等等。

安装过程就不说了,无非就是configure/make/make install,配置样例也都有

在昨天配置varnish的时候发现,man里提供的配置样例中有一段是这样的

if (req.http.Authenticate || req.http.Cookie) {
pass;
}

但是实际上这段配置在测试过程中造成了一些麻烦,情况很奇怪,怀疑是varnish的bug。网站图片显示不正常,文字貌似没问题,抓包看,竟然发现在客户端请求图片的时候,varnish把上一次回送的HTML文本内容又送了一遍。

由于不太清楚pass和pipe的区别,出于尝试目的于是我把配置改为:

if (req.http.Authenticate ){
pass;
}
if(req.http.Cookie) {
pipe;
}

也就正常了。

于是再次尝试一下,暂时把自己BLOG的域名指到一台跑varnish的烂PC上,测试一下看看,获取些实际运行经验。打算跑个几天再改回来。

昨天下班后修改DSN,本地大约过了5个小时,生效,访问www.2tutu.com 通过varnish缓存。

早上来看了下,varnish总共处理1395个请求,缓存命中是1132,看样子对于ZBLOG这样静态内容为主的站点,缓存命中还是比较高的。

自己的网站访问量并不大,其实最好能找个访问量比较大的站点进行一下实际测试,呵呵。

man page意译如下:

VCL语法比较简单,和C类似,if(){}的形式,=和==的区别,!、&&和||等等。但\符号没有特别的意思。
VCL里除了用==、!、&&、||做逻辑判断意外,还可以用~来表示与正则表达式或ACL的匹配。
VCL其实只是配置,并不是真正的编程语言,没有循环,没有自定义变量。

声明Backend
backend 名称 {
set backend.host = "域名";
set backend.port = "端口";
}
比如
backend www {
set backend.host = "www.example.com";
set backend.port = "http";
}
声明的Backend可以用在判断请求针对哪个后端服务器
if (req.http.host ~ "^(www.)?example.com$") {
{
set req.backend = www;
}

声明ACL
acl 名称 {
"IP";
"IP子网"/反掩码位数;
! "IP或IP子网"/反掩码位数;
}
比如
acl local {
"locahost"; /* myself */
"10.0.0.1"/8; /* and everyone on the local network */
! "10.0.0.23"; /* except for the dialin router */
}
判断ACL也很简单
if (client.ip ~ local) {
pipe;
}

还可以定义子程序
sub pipe_if_local {
if (client.ip ~ local) {
pipe;
}
}
用call来调用
call pipe_if_local;

内置的例程
vcl_recv
有请求到达后成功接收并分析时被调用,一般以以下几个关键字结束。
error code [reason] 返回code给客户端,并放弃处理该请求
pass 进入pass模式,把控制权交给vcl_pass
pipe 进入pipe模式,把控制权交给vcl_pipe
lookup 在缓存里查找被请求的对象,根据查找结果把控制权交给vcl_hit或vcl_miss

vcl_pipe
进入pipe模式时被调用。请求被直接发送到backend,后端和客户端之间的后继数据不进行处理,只是简单传递,直到一方关闭连接。一般以以下几个关键字结束。
error code [reason]
pipe

vcl_pass
进入pass模式时被调用。请求被送到后端,后端应答数据送给客户端,但不进入缓存。同一连接的后继请求正常处理。一般以以下几个关键字结束。
error code [reason]
pass

vcl_hash
目前不使用

vcl_hit
在lookup以后如果在cache中找到请求的内容事调用。一般以以下几个关键字结束。
error code [reason]
pass
deliver 将找到的内容发送给客户端,把控制权交给vcl_deliver.

vcl_miss
lookup后但没有找到缓存内容时调用,可以用于判断是否需要从后端服务器取内容。一般以以下几个关键字结束。
error code [reason]
pass
fetch 从后端取得请求的内容,把控制权交给vcl_fetch.

vcl_fetch
从后端取得内容后调用。一般以以下几个关键字结束。
error code [reason]
pass
insert 将取到的内容插入缓存,然后发送给客户端,把控制权交给vcl_deliver

vcl_deliver
缓存内容发动给客户端前调用。一般以以下几个关键字结束。
error code [reason]
deliver 内容发送给客户端

vcl_timeout
在缓存内容到期前调用。一般以以下几个关键字结束。
fetch 从后端取得该内容
discard 丢弃该内容

vcl_discard
由于到期或者空间不足而丢弃缓存内容时调用。一般以以下几个关键字结束。
discard 丢弃
keep 继续保留在缓存里

如果这些内置例程没有被定义,则执行缺省动作

一些内置的变量
now 当前时间,标准时间点(1970?)到现在的秒数

backend.host 后端的IP或主机名
backend.port 后端的服务名或端口

请求到达后有效的变量
client.ip 客户端IP
server.ip 服务端IP
req.request 请求类型,比如GET或者HEAD或者POST
req.url 请求的URL
req.proto 请求的HTTP版本号
req.backend 请求对应的后端
req.http.header 对应的HTTP头

往后段的请求时有效的变量
bereq.request 比如GET或HEAD
bereq.url URL
bereq.proto 协议版本
bereq.http.header HTTP头

从cache或后端取到内容后有效的变量
obj.proto HTTP协议版本
obj.status HTTP状态代码
obj.response HTTP状态信息
obj.valid 是否有效的HTTP应答
obj.cacheable 是否可以缓存的内容,也就是说如果HTTP返回是200、203、300、301、302、404、410并且有非0的生存期,则为可缓存
obj.ttl 生存期,秒
obj.lastuse 上一次请求到现在间隔秒数

对客户端应答时有效的变量
resp.proto response的HTTP版本
resp.status 回给客户端的HTTP状态代码
resp.response 回给客户端的HTTP状态信息
resp.http.header HTTP头

变量可以通过set来赋值或通过remove来删除(清空)
sub vcl_recv {
if (req.http.host ~ "^(www.)?example.com$") {
set req.http.host = "www.example.com";
}
}

sub vcl_fetch {
remove obj.http.Set-Cookie;
}

- -------------------------------------------------------------------------------------------------
 

我在设计系统架构时,进行了大胆的尝试,只用6台Web服务器(除开FLV视频存储服务器),达到了可承受4000万PV(页面访问量)的性能:

抛弃了 Apache,因为它能承受的并发连接相对较低;
抛弃了 Squid,因为它在内存利用、访问速度、并发连接、清除缓存等方面不如 Varnish;
抛弃了 PHP4,因为 PHP5 处理面向对象代码的速度要比 PHP4 快,另外,PHP4 已经不再继续开发;
抛弃了 F5 BIG-IP 负载均衡交换机,F5 虽然是个好东西,但由于价格不菲,多个部门多个产品都运行在其之上,流量大、负载高,从而导致性能大打折扣;

利用 Varnish cache 减少了90%的数据库查询,解决了MySQL数据库瓶颈;
利用 Varnish cache 的内存缓存命中加快了网页的访问速度;
利用 Nginx + PHP5(FastCGI) 的胜过Apache 10倍的高并发性能,以最少的服务器数量解决了PHP动态程序访问问题;
利用 Memcached 处理实时数据读写;
利用 HAProxy 做接口服务器健康检查;

经过压力测试,每台Web服务器能够处理3万并发连接数,承受4千万PV完全没问题。

保证4千万PV的并发连接数:(40000000PV / 86400秒 * 10个派生连接数 * 5秒内响应 * 5倍峰值) / 6台Web服务器 = 19290连接数

-------------------------------------------------------------------------------------------------------

创建Varnish配置文件:
vi /usr/local/varnish/vcl.conf

输入以下内容:
backend myblogserver {
set backend.host = "192.168.0.5";
set backend.port = "80";
}

acl purge {
"localhost";
"127.0.0.1";
"192.168.1.0"/24;
}

sub vcl_recv {
if (req.request == "PURGE") {
if (!client.ip ~ purge) {
error 405 "Not allowed.";
}
lookup;
}

if (req.http.host ~ "^blog.s135.com") {
set req.backend = myblogserver;
if (req.request != "GET" && req.request != "HEAD") {
pipe;
}
else {
lookup;
}
}
else {
error 404 "Zhang Yan Cache Server";
lookup;
}
}

sub vcl_hit {
if (req.request == "PURGE") {
set obj.ttl = 0s;
error 200 "Purged.";
}
}

sub vcl_miss {
if (req.request == "PURGE") {
error 404 "Not in cache.";
}
}

sub vcl_fetch {
if (req.request == "GET" && req.url ~ "\.(txt|js)$") {
set obj.ttl = 3600s;
}
else {
set obj.ttl = 30d;
}
}

这里,我对这段配置文件解释一下:
(1)、Varnish通过反向代理请求后端IP为192.168.0.5,端口为80的web服务器;
(2)、Varnish允许localhost、127.0.0.1、192.168.0.***三个来源IP通过PURGE方法清除缓存;
(3)、Varnish对域名为blog.s135.com的请求进行处理,非blog.s135.com域名的请求则返回“Zhang Yan Cache Server”;
(4)、Varnish对HTTP协议中的GET、HEAD请求进行缓存,对POST请求透过,让其直接访问后端Web服务器。之所以这样配置,是因为POST请求一般是发送数据给服务器的,需要服务器接收、处理,所以不缓存;
(5)、Varnish对以.txt和.js结尾的URL缓存时间设置1小时,对其他的URL缓存时间设置为30天。
5、启动Varnish

ulimit -SHn 51200
/usr/local/varnish/sbin/varnishd -n /var/vcache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:80 -s file,/var/vcache/varnish_cache.data,1G -g www -u www -w 30000,51200,10 -T 127.0.0.1:3500 -p client_http11=on

6、启动varnishncsa用来将Varnish访问日志写入日志文件:

/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/varnish.log &

7、如果想配置成开机自动启动Varnish

vi /etc/rc.local

在末尾增加以下内容:

ulimit -SHn 51200
/usr/local/varnish/sbin/varnishd -n /var/vcache -f /usr/local/varnish/vcl.conf -a 0.0.0.0:80 -s file,/var/vcache/varnish_cache.data,1G -g www -u www -w 30000,51200,10 -T 127.0.0.1:3500 -p client_http11=on
/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/youvideo.log &

8、优化Linux内核参数

vi /etc/sysctl.conf

在末尾增加以下内容:

net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 5000    65000

再看看如何管理Varnish:
1、查看Varnish服务器连接数与命中率:

/usr/local/varnish/bin/varnishstat -n /var/vcache

输出的结果如下图显示: 

点击查看原图
2、通过Varnish管理端口进行管理:
用help看看可以使用哪些Varnish命令:

/usr/local/varnish/bin/varnishadm -T 127.0.0.1:3500 help

3、通过Varnish管理端口,使用正则表达式批量清除缓存:
(1)、例:清除类似http://blog.s135.com/a/zhangyan.html的URL地址):

/usr/local/varnish/bin/varnishadm -T 127.0.0.1:3500 url.purge /a/

(2)、例:清除类似http://blog.s135.com/tech的URL地址:

/usr/local/varnish/bin/varnishadm -T 127.0.0.1:3500 url.purge w*$

(3)、例:清除所有缓存:
/usr/local/varnish/bin/varnishadm -T 127.0.0.1:3500 url.purge *$

附1:2007年12月10日,我写了一个每天0点运行,按天切割Varnish日志,生成一个压缩文件,同时删除上个月旧日志的脚本(/var/logs/cutlog.sh):
/var/logs/cutlog.sh文件内容如下:

#!/bin/sh
# This file run at 00:00
date=$(date -d "yesterday" +"%Y-%m-%d")
pkill -9 varnishncsa
mv /var/logs/youvideo.log /var/logs/${date}.log
/usr/local/varnish/bin/varnishncsa -n /var/vcache -w /var/logs/youvideo.log &
mkdir -p /var/logs/youvideo/
gzip -c /var/logs/${date}.log > /var/logs/youvideo/${date}.log.gz
rm -f /var/logs/${date}.log
rm -f /var/logs/youvideo/$(date -d "-1 month" +"%Y-%m*").log.gz

设置在每天00:00定时执行:

/usr/bin/crontab -e
0 0 * * * /bin/sh /var/logs/cutlog.sh
 

此条目发表在web server分类目录,贴了标签。将固定链接加入收藏夹。