-- 把squid换成varnish来实现反向代理 www.varnish-cache.org client 张三 | | varnish 李四 | | web 王五 ftp 马六 pass 当vcl_recv调用 pass 函数时,pass将当前请求直接转发到后端服务器。而后续的请求仍然通过varnish处理。 pipe 而pipe模式则不一样,当vcl_recv判断 需要调用 pipe 函数时,varnish会在客户端和服务器之间建立一条直接的连接 ,之后客户端的所有请求都直接发送给服务器,绕过varnish,不再由varnish检查请求,直到连接断开。 vcl_recv --> vcl_pipe vcl_recv --> vcl_pass vcl_recv --> lookup (hash) --> vcl_miss --> vcl_fetch(vcl_backend_response) --> vcl_deliver vcl_recv --> lookup (hash) --> vcl_hit --> vcl_deliver client 172.16.2.x | | 172.16.2.35 varnish 192.168.1.1 | | |---------------------| web1 web2 192.168.1.128 192.168.1.129 软件包路径在 笔记目录/program/varnish_soft/ ---------------------------------------------- 4.0.3版本的源码编译安装方法(仅做参考,下面使用rpm版本来做) yum install pcre-devel tar xf docutils-0.12.tar.gz -C /usr/src/ cd /usr/src/docutils-0.12/ python setup.py install tar xf varnish-4.0.3.tar.gz -C /usr/src/ cd /usr/src/varnish-4.0.3/ ./configure --prefix=/usr/local/varnish make make install cp /usr/local/varnish/share/man/man7/vcl.7 /usr/share/man/man7/ ------------------------------------------------ 4.0.3版本的rpm版安装方法: 软件包路径如下(下载地址为http://repo.varnish-cache.org/redhat/varnish-4.0/el6/x86_64/varnish/和http://dl.fedoraproject.org/pub/epel/6Server/x86_64/) 软件包主要为下面几个 jemalloc-3.6.0-1.el6.x86_64.rpm varnish-4.0.3-1.el6.x86_64.rpm varnish-libs-4.0.3-1.el6.x86_64.rpm varnish-docs-4.0.3-1.el6.x86_64.rpm 安装顺序 # rpm -ivh jemalloc-3.6.0-1.el6.x86_64.rpm # rpm -ivh varnish-4.0.3-1.el6.x86_64.rpm varnish-libs-4.0.3-1.el6.x86_64.rpm varnish-docs-4.0.3-1.el6.x86_64.rpm 配置rpm版varnish # vim /etc/sysconfig/varnish 66 VARNISH_LISTEN_PORT=80 --这是listen的端口,默认为6081,我这里改为80(因为我的varnish在这里为最前端) 69 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 --管理端口的监听地址,保持默认值 70 VARNISH_ADMIN_LISTEN_PORT=6082 --管理端口,我这里保持默认值 例1:varnish直接代理后台一个web服务器 client 172.16.2.x | | 172.16.2.35 varnish 192.168.1.1 | | | web1 192.168.1.128 配置rpm版本主配置文件 # vim /etc/varnish/default.vcl vcl 4.0; --4.0.3版本,必须要加这一句指定为4.0版的vcl语法 backend web1 { .host = "192.168.1.128"; .port = "80"; } 启动varnish服务 # /etc/init.d/varnish start (--或者直接使用命令来启动:# varnishd -f /etc/varnish/default.vcl -a 0.0.0.0:80 -s malloc -T 127.0.0.1:6082) # lsof -i:80 # lsof -i:6082 客户端可以通过elinks 172.16.2.35或者curl -I 172.16.2.35的方法来验证 例2:varnish代理后台两个不同域名的web服务器 client 172.16.2.x | | 172.16.2.35 varnish 192.168.1.1 | | |---------------------| web1 web2 192.168.1.128 192.168.1.129 www.aaa.com www.bbb.com # vim /etc/varnish/default.vcl vcl 4.0; backend web1 { .host = "192.168.1.128"; .port = "80"; } backend web2 { .host = "192.168.1.129"; .port = "80"; } sub vcl_recv { if (req.http.host ~ "aaa.com$") { set req.backend_hint = web1; } else { set req.backend_hint = web2; } } --上面表示访问以aaa.com结尾的域名请求会给web1,bbb.com结尾的域名请求会给web2 重启varnish服务 # /etc/init.d/varnish restart 测试 在客户端 cat /etc/hosts 172.16.2.35 www.aaa.com 172.16.2.35 www.bbb.com # elinks www.aaa.com/1 --访问此域名的都会显示web1的内容 # elinks www.bbb.com/1 --都会显示web2的内容 扩展,如果这两个网站是做的虚拟主机,那么依不同类型的虚拟主机(基于IP,基于端口,基于域名),配置方法不一样 就基于域名的写法如下(基于IP和端口的就不例举了) backend web1 { .host = "192.168.1.128"; --这里用IP,也可以写www.aaa.com .port = "80"; } backend web2 { .host = "192.168.1.128"; --这里用IP,也可以写www.bbb.com .port = "80"; } 例3:实现代理同一个网站内容分割,如www.aaa.com/sports/和www.aaa.com/news/会把请求分发给不同的后台web client 172.16.2.x | | 172.16.2.35 varnish 192.168.1.1 | | |---------------------| web1 web2 192.168.1.128 192.168.1.129 www.aaa.com/sports/ www.aaa.com/news/ vcl 4.0; backend web1 { .host = "192.168.1.128"; .port = "80"; } backend web2 { .host = "192.168.1.129"; .port = "80"; } sub vcl_recv { if (req.url ~ "^/sports/") { set req.backend_hint = web1; } if (req.url ~ "^/news/") { set req.backend_hint = web2; } } 扩展:上面是实现的url路径的负载分离,可以引出针对文件类型的分离(动静分离) 只需要把 sub vcl_recv { if (req.url ~ "\.(txt|html|css|jpg|jpeg|gif)$") { --在这里写上你想让它访问web1的文件类型就可以 set req.backend_hint = web1 ; } else { set req.backend_hint = web2 ; } } 例4:把www.xxx.com/sports/下的请求,使用rr算法分别调度给web1和web2 vcl 4.0; backend web1 { .host = "192.168.1.128"; .port = "80"; } backend web2 { .host = "192.168.1.129"; .port = "80"; } import directors; sub vcl_init { new rr = directors.round_robin(); rr.add_backend(web1); rr.add_backend(web2); } sub vcl_recv { if (req.url ~ "^/sports/") { set req.backend_hint = rr.backend(); } if (req.url ~ "^/news/") { set req.backend_hint = web2; } } ------------------------------------------------------------ 例5,后台web服务器的健康检查 vcl 4.0; probe backend_healthcheck { .url = "/test.txt"; .timeout = 0.3 s; .window = 5; .threshold = 3; .initial = 3; } backend web1 { .host = "192.168.1.128"; .port = "80"; .probe = backend_healthcheck; } backend web2 { .host = "192.168.1.129"; .port = "80"; .probe = backend_healthcheck; } import directors; sub vcl_init { new rr = directors.round_robin(); rr.add_backend(web1); rr.add_backend(web2); } sub vcl_recv { if (req.url ~ "^/sports/") { set req.backend_hint = rr.backend(); } if (req.url ~ "^/news/") { set req.backend_hint = web2; } } --------------------------------------- 综合配置实例: vcl 4.0; probe backend_healthcheck { .url = "/test.txt"; .timeout = 0.3 s; .window = 5; .threshold = 3; .initial = 3; } backend web1 { .host = "192.168.1.128"; .port = "80"; .probe = backend_healthcheck; } backend web2 { .host = "192.168.1.129"; .port = "80"; .probe = backend_healthcheck; } import directors; sub vcl_init { new rr = directors.round_robin(); rr.add_backend(web1); rr.add_backend(web2); } acl purgers { "127.0.0.1"; "192.168.1.0"/24; } sub vcl_recv { if (req.method == "GET" && req.http.cookie) { return(hash); } if (req.url ~ "test.txt") { return(pass); } if (req.method == "PURGE") { if (!client.ip ~ purgers) { return(synth(405,"Method not allowed")); } return(hash); } if (req.http.X-Forward-For) { set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip; } else { set req.http.X-Forward-For = client.ip; } if (req.http.host ~ "www.cluster.com") { set req.backend_hint = rr.backend() ; } else { return(synth(404,"error domain name")); } } sub vcl_miss { return(fetch); } sub vcl_hit { if (req.method == "PURGE") { unset req.http.cookie; return(synth(200,"Purged")); } } sub vcl_backend_response { if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") { set beresp.ttl = 10s; } if (bereq.url ~ "\.(html|css|js)$") { set beresp.ttl = 20s; } if (beresp.http.Set-Cookie) { return(deliver); } } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "@_@ HIT from " + server.ip; } else { set resp.http.X-Cache = "@_@ oh,god,MISS"; } } ----------------------------------------------------- 补充一: 有一个问题:就是后台的web有大量的健康检查日志,如果配置的是每5秒一次检查的话,那么apache每5秒就会有这么一条; 想要清除它的话 # vim /etc/httpd/conf/httpd.conf SetEnvIf Request_URI "^/test\.txt$" dontlog --加上这一句 CustomLog logs/access_log combined env=!dontlog --在你希望不记录与test.txt有关的日志后面加上env=!dontlog /etc/init.d/httpd restart 那上面的方法与架构前端是varnish或squid或nginx或haproxy等无关,上面的配置是用的apache本身的参数 当然如果你不会这种方法,也可以用笨方法,写一个脚本,定期或者在日志轮转前清除健康检查日志就可以了 # vim clear_healtycheck_log.sh #!/bin/bash sed -i '/test.txt/d' /var/log/httpd/access_log kill -USR1 `cat /var/run/httpd/httpd.pid` -------------------------------------------------------------- 补充二: 关于如何让后台的web服务器显示的IP是客户端的真实IP,而不是varnish的内网IP的做法 首先在vanrish配置里有下面一段相关配置(在4.0.3版测试时,不要这一段也可以,说明应该默认配置就是这个) if (req.http.X-Forward-For) { set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip; } else { set req.http.X-Forward-For = client.ip; } 然后在后面的web服务器里做下面的修改 # vim /etc/httpd/conf/httpd.conf LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnishcombined --加上这一句,这是表示增加了一个日志格式,这个格式名为varnishcombined CustomLog logs/access_log varnishcombined env=!dontlog --修改这一句,把原来它使用的combined格式换成varnishcombined格式 # /etc/init.d/httpd restart 然后使用客户端去访问测试,后面apache显示的IP是客户端的真实IP了 但是这里有一个问题:如果这次访问是第一次访问,日志里才会有;如果是被varnish命中了,则varnish直接返回给客户端了,所以后台的web这里就没有记录了 另一个解决方法: 那就是不使用后面的web的日志,而直接使用varnish的日志 /etc/init.d/varnishncsa start --启动varnish日志服务 # cat /var/log/varnish/varnishncsa.log --日志路径 ====================================== 补充三: # varnishstat --查看一些参数指标 ============================================================= 补充四: 尝试使用ab压力测试 非varnish的环境,测试准备 1,先关闭varnish,然后写一条DNAT iptables -t nat -A PREROUTING -i br0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.128 2,关闭web2,只留下web1,单网站测试 3,在web1上route add default gw 192.168.1.1把网关指向varnish内网IP,主要是为了数据能够回去 然后在客户使用下面命令来测试 # ab -c 100 -n 1000 http://www.cluster.com/1.txt Server Software: Apache/2.2.15 Server Hostname: www.cluster.com Server Port: 80 Document Path: /1.txt Document Length: 4 bytes Concurrency Level: 100 Time taken for tests: 0.343 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 271000 bytes HTML transferred: 4000 bytes Requests per second: 2913.94 [#/sec] (mean) Time per request: 34.318 [ms] (mean) Time per request: 0.343 [ms] (mean, across all concurrent requests) Transfer rate: 771.17 [Kbytes/sec] received 有varnish环境测试准备 1,去掉上面的iptables, 2,启动varnish 然后在客户端测试 # ab -c 100 -n 1000 http://www.cluster.com/1.txt Server Software: Apache/2.2.15 Server Hostname: www.cluster.com Server Port: 80 Document Path: /1.txt Document Length: 4 bytes Concurrency Level: 100 Time taken for tests: 0.103 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 377951 bytes HTML transferred: 4056 bytes Requests per second: 9729.05 [#/sec] (mean) Time per request: 10.278 [ms] (mean) Time per request: 0.103 [ms] (mean, across all concurrent requests) Transfer rate: 3590.92 [Kbytes/sec] received 最后比较结果,结论是varnish处理速度比非varnish环境快(还可以与squid做个对比,varnish比squid也要快)