自由论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 514|回复: 0

[学习笔记]反向代理解析

[复制链接]

85

主题

97

帖子

9651

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9651
发表于 2016-1-10 15:55:51 | 显示全部楼层 |阅读模式
把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也要快)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Prostar Inc.

GMT+8, 2024-3-29 10:00 , Processed in 0.035426 second(s), 9 queries , Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表