套句马哥经常说的话,cache is king,在现在的企业架构中,都用到了缓存服务器,缓存,可以减轻对后端服务器的压力,而且对于请求比较频繁的热区数据,我们如果缓存在缓存服务器上,都会增加被命中的概率,对于大并发的请求情况下,对于后端的服务器也是一种保护。
下面我们要介绍的是缓存服务器中的新秀,varnish,这是一款轻量级的缓存服务,相比squid,性能更高,速度更快,管理上还更加方便,被说烂的例子就是挪威最大的在线报纸,用3台varnish替换掉了12台squid,性能上还有提升,可见varnish的地位上升之快。
varnish于nginx有着众多的相似之处,它们都是各自领域的新秀,而且,都是有一个master进程,多个子进程所构成,这次,我要利用varnish的缓存功能,加上haproxy的调度和高可用性,搭建一个高可用,且具有很强缓存的web服务
系统:CentOS 6.5
服务器数量:5台
所需要的软件及下载地址:
varnish-3.0.5-1.el6.x86_64.rpm
varnish-libs-3.0.5-1.el6.x86_64.rpm
https://repo.varnish-cache.org/redhat/varnish-3.0/el6/x86_64/varnish/
haproxy.x86_64 0:1.4.24-2.el6 #通过yum安装
首先,我们先在node3、和node4这两个主机上,提供web服务,提供主页
node3上:
[root@node3 ~]# cat /var/www/html/index.html
I am a linux lover node4上:
[root@node4 ~]# cat /var/www/html/index.html
shell is difficult to learn 然后,将这两个web服务启动
[root@node3 ~]# service httpd start
[root@node4 ~]# service httpd start 后端的web服务已完成,下面就是搭建我们的varnish缓存服务器了
在node1和node2上都执行下列操作
[root@node1 ~]# yum install varnish-libs-3.0.5-1.el6.x86_64.rpm varnish-3.0.5-1.el6.x86_64.rpm #可以自动解决依赖关系 备份varnish的配置文件
[root@node1 ~]# cp /etc/varnish/default.vcl /etc/varnish/default.vcl.bak 编辑varnish的启动脚本的配置文件,让其监听在80端口上,而且,指定存储类型为mallo
VARNISH_LISTEN_PORT=80 #监听在80端口
VARNISH_STORAGE_SIZE=100M #缓存大小为100M
VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" #这里是调用上面的变量 然后,启动varnish服务
[root@node2 ~]# service varnish start
[root@node1 ~]# ss -tlnp | grep 80 #此时,80端口已经被监听(最好确保我们的其他web程序是关闭的)
LISTEN 0 128 :::80 :::* users:(("varnishd",8840,8))
LISTEN 0 128 *:80 *:* users:(("varnishd",8840,7)) 登录到我们的varnish的控制端查看
[root@node2 ~]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 -S:指定密钥文件
-T:指定可以登录的管理员的地址和端口,这个是在/etc/sysconfig/varnish文件中定义的
实验要求:(对varnish而言)
1、要通过负载均衡的方式调度后端的两个web服务器
2、可以在后端的web服务器的日志文件上,查看真正访问web服务的客户端的IP地址
3、实现对后端两个web服务器健康状态的检测
使用轮询的调度方法
在/etc/varnish/目录中新建一个lb.vcl的文件,作为负载均衡作用的配置文件,配置如下
backend web1 {
.host = "192.168.77.13";
.port = "80";
}
backend web2 {
.host = "192.168.77.14";
.port = "80";
}
director webs round-robin { #使用轮询的调度算法
{.backend = web1;}
{.backend = web2;}
}
sub vcl_recv {
set req.backend = webs; #要调用上面这个组
} 然后,我们可以通过上面的管理接口,使用这个配置文件了
varnish> vcl.load lb ./lb.vcl #加载这个配置
200
VCL compiled. #这样就是编译成功的提示
varnish> vcl.use lb #使用上面定义的配置
200 此时,我们在浏览器中测试,先访问node1,再访问node2


之后,无论怎么刷新都不改变了,调出开发者工具查看
我们可以查看我们的后端web服务器的日志文件
[root@node4 ~]# tail /var/log/httpd/access_log
192.168.77.12 – -
[20/Sep/2014:20:32:28 +0800] "GET /favicon.ico HTTP/1.1" 404 288 "-"
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101
Firefox/32.0"
192.168.77.11 – - [20/Sep/2014:20:35:23 +0800] "GET /
HTTP/1.1" 200 37 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114
Safari/537.36 此时,显示的是我们的varnish服务器的地址
在后端记录客户端IP地址
更改配置文件,使其能够记录客户端的IP地址,在上面的实验上扩展
[root@node1 varnish]# cp lb.vcl log.vcl
[root@node1 varnish]# vim log.vcl
backend web1 {
.host = "192.168.77.13";
.port = "80";
}
backend web2 {
.host = "192.168.77.14";
.port = "80";
}
director webs round-robin {
{.backend = web1;}
{.backend = web2;}
}
sub vcl_recv {
set req.http.X-Forwarded-For = clinet.ip;
if (req.url ~ "index.html$") {
return (pass);
}
set req.backend = webs;
} 两个web服务器都做修改
然后,将后端的web记录日志的格式修改如下
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 重启httpd服务
[root@node3 ~]# service httpd restart 回到varnish服务器,加载新的配置
varnish> vcl.load log ./log.vcl
200
VCL compiled.
varnish> vcl.use log
200 到浏览器中,分别访问
发现,网页发生了变化,这是缓存时间结束了,新的请求返回新的网页,之后,连续刷新时,就不会缓存了
查看我们后端web服务器的日志文件
[root@node3 ~]# tail /var/log/httpd/access_log
192.168.77.11 –
- [20/Sep/2014:20:35:24 +0800] "GET /favicon.ico HTTP/1.1" 404 288 "-"
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/35.0.1916.114 Safari/537.36"
[root@node4 ~]# tail /var/log/httpd/access_log
192.168.77.1,
192.168.77.1 – - [20/Sep/2014:20:54:51 +0800] "GET / HTTP/1.1" 200 37
"-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/35.0.1916.114 Safari/537.36" 此时,上面记录的都是当前windows主机的地址了,如果没有,可以多次刷新网页后查看,可能还是缓存命中
健康检查机制:
如果,我们的后端web宕机了呢?我们是否发觉?下面引入健康检查机制
[root@node1 varnish]# cp log.vcl health.vcl
[root@node1 varnish]# vim health.vcl
probe healthchk { #定义一个健康检测的标准
.url = "/";
.interval = 5s;
.timeout = 2s;
}
backend web1 {
.host = "192.168.77.13";
.port = "80";
.probe = healthchk; #调用健康检测
}
backend web2 {
.host = "192.168.77.14";
.port = "80";
.probe = healthchk;
}
director webs round-robin {
{.backend = web1;}
{.backend = web2;}
}
sub vcl_recv {
set req.http.X-Forwarded-For = client.ip;
if (req.url ~ "index.html$") {
return (pass);
}
set req.backend = webs;
} 加载新的配置,并使用
varnish> vcl.load health ./health.vcl
200
VCL compiled.
varnish> vcl.use health
200 此时,我们可以将后端的两个web服务器的http服务都停掉
[root@node4 ~]# service httpd stop 在我们的浏览器中查看
此时,健康状态就显示出来了,不过,你可能要等缓存失效后,才能刷出这个网页
最后,我们可以在前端加上一个haproxy,作为这两个varnish缓存服务器的负载均衡器
安装haproxy,这里使用yum的方式
[root@hap ~]# yum install -y haproxy 备份配置文件,并且对配置文件进行编辑
[root@hap ~]# cd /etc/haproxy/
[root@hap haproxy]# cp haproxy.cfg haproxy.cfg.bak
[root@hap haproxy]# vim haproxy.cfg
frontend main *:80
maxconn 3000
default_backend webs
backend webs
balance uri
server varnish1 192.168.77.11 check port 80
server varnish2 192.168.77.12 check port 80
server back 127.0.0.1:8080 backup
stats enable #开启status功能
stats admin if TRUE #开启管理功能
stats hide-version #隐藏版本号
stats scope . #当前作用域
stats uri /admin?stas #自定义uri
stats realm admin\ authorizen #用户认证模式
stats auth hapadmin:varnish #认证的用户名和密码 然后,启动haproxy服务
[root@hap haproxy]# service haproxy start
[root@hap haproxy]# ss -tlnp | grep 80 #此时,已经监听80端口
LISTEN 0 128 *:80 *:* users:(("haproxy",2497,4)) 将后端的两个web服务启动,然后,在浏览器中访问
此时,还可以查看我们的status状态页
此时,我们还可以提供sorry server,即这里的back,在haproxy的本机上
[root@hap haproxy]# cat /var/www/html/index.html
Sorry! please wait! 同时,还得修改httpd的配置文件,使其监听在8080端口上,因为80被haproxy占用
[root@hap haproxy]# vim /etc/httpd/conf/httpd.conf
Listen 8080 #修改此项
并且,把http服务启动
[root@hap haproxy]# service httpd start 我们可以在stats页面上,让后端的两个varnish服务器停止工作,刷浏览器
访问我们的站点

当后端主机宕机后,我们的haproxy上的sorry server就能派的上用场了,详细的varnish的内容会在近期的varnish原理知识中发布出来,这也是自己的任务。
|