利用apache的proxy来做负载均衡

虽然很早以前就知道得用apche的mod_proxy可以用来做负载均衡,可由于太懒,一直都没有去做。今天刚好工作上也要做这个,所以就实验了一把。

要使用apache的负载均衡功能,首得得开启下面这几个模块:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so

其中mod_proxy提供代理服务器功能,mod_proxy_balancer提供负载均衡功能, mod_proxy_http让代理服务器能支持HTTP协议。

然后,要在httpd.conf中加入这么一段配置:

ProxyRequests Off
<Proxy balancer://mycluster>
    BalancerMember http://192.168.0.1
    BalancerMember http://192.168.0.2
</Proxy>
ProxyPass /mycluster !
ProxyPass / balancer://mycluster
<Location /mycluster>
    SetHandler balancer-manager
    Order Deny,Allow
    Deny from all
    Allow from localhost
</Location>

从上面的 ProxyRequests Off 这条可以看出,实际上负载均衡器就是一个反向代理, 只不过它的代理转发地址不是某台具体的服务器,而是一个 balancer:// 协议:

ProxyPass / balancer://mycluster

下面那段是用来监视负载均衡的工作情况的,然后访问 http://localhost/mycluster/ 即可看到负载均衡的工作状况。你也可以利用这个工具将其中某一个终端要暂时从集群中移出,或者临时修改某个终端的参数(如factor等)。

这个地方要特别注意的是下面这行配置:

ProxyPass /mycluster !

如果没有这行配置,当你访问http://localhost/mycluster/也会被转发到终端上去。

改完之后重启服务器,访问你的Apache所在服务器的地址,即可看到负载均衡的效果了。 打开 mycluster的界面,可以看到请求是平均分配的。

当然,你也可以像我这个配置这样修改其中的某些参数,来获得最大的负载均衡的功效

ProxyRequests Off
ProxyPass /mycluster !
ProxyPass / balancer://mycluster/ stickysession=BALANCEID
ProxyPassReverse / http://192.168.0.1/
ProxyPassReverse / http://192.168.0.2/
<Proxy balancer://mycluster>
        BalancerMember http://192.168.0.1 route=http1 loadfactor=7
        BalancerMember http://192.168.0.2 route=http2 loadfactor=3
        ProxySet lbmethod=byrequests
</Proxy>
<Location /mycluster>
    SetHandler balancer-manager
    Order Deny,Allow
    Deny from all
    Allow from localhost
</Location>

其中,stickysession=BALANCEID设置根据下面的route=http1/2来进行session的绑定。因为很多网站的变量,如登陆信息等,可能是储存在服务器端的内存中的,如果不设置这个变量,用户来访问是还是不段的在不同的终端之间切换,用户就会不停的退出
loadfactor=7这个是设置不同的终端的负载均衡的权重,数值越来,转发的数量就越多。
而ProxySet lbmethod=byrequests是用来设置负载均衡的算法。通常有三种取值:byrequests(按照请求次数均衡,默认值),bytraffic(按照流量均衡),bybusyness(按照繁忙程度均衡)。

为phpwind做代理加速镜像

今天给风云墙做了一个教育网的代理服务器来给教育网的用户加速。本来以为是一个很简单的问题,结果却大费周折。

第一打算是用squid来做,结果却由于原来的80端口被占用,暂时找不到一个圆满的解决方案,只好放弃。

80端口已经被apache占用了,也就只好用mod_proxy来做了。
在apache中加上这么一个vhost,理论上应该是可以了,但是,里面的链接还是指向原来的http://bbs.clwind.net,并不像反向代理所期待的http://edu.clwind.net.

<VirtualHost *:80>
    ServerAdmin myhnet@gmail.com
    DocumentRoot /none
    ServerName  edu.clwind.net
    ProxyRequests Off
    ProxyPass  / http://bbs.clwind.net
    ProxyPassReverse / http://bbs.clwind.net
</VirtualHost>

开始一直以为是反向代理的问题(我对反向代理不太熟悉),查找了好久,也没发现问题所在(本来就不是他的问题,怎么可能发现得了)。最好做了一个最简单的网站来做源站,才发现原来是phpwind的head部分的问题。

在phpwind的header.html中,给页面加上了一个base标签

<base id="headbase" href="$db_bbsurl/" />

base标签的作用是给网页中的链接指定一个默认的URL前缀或者是指定一个target,比如:

<base target="_blank" />

而在phpwind中,$db_bbsurl这个变量是由PHP系统变量$_SERVER[HTTP_HOST]得来的。

但是这个变量在使用了反向代理之后,并不是我们访问的URL,这个时候介入了一个新的变量,只有在使用代理访问之后才会有的变量:$_SERVER[HTTP_X_FORWARDED_HOST]。这个变量才是我们访问的URL。

这样,为了反向代理能够正常使用,我们需要更改phpwind的代码。
打开global.php

解决base标签的问题
找到:

$R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_HOST]".substr($tmp,0,strrpos($tmp,'/')));

修改为:

if ($_SERVER[HTTP_X_FORWARDED_HOST]) {
        $R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_X_FORWARDED_HOST]".substr($tmp,0,strrpos($tmp,'/')));
} else {
        $R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_HOST]".substr($tmp,0,strrpos($tmp,'/')));
}

解决前台发帖的非法操作问题
同样在global.php中:
找到:

list($http_host) = explode(':',$_SERVER['HTTP_HOST']);

修改为:

if ($_SERVER[HTTP_X_FORWARDED_HOST]){
                        list($http_host) = explode(':',$_SERVER['HTTP_X_FORWARDED_HOST']);
                } else {
                        list($http_host) = explode(':',$_SERVER['HTTP_HOST']);
                }

解决多重代理IP unknow问题
还是global.php
找到:

$onlineip = $_SERVER['HTTP_X_FORWARDED_FOR'];

改为:

$ip_temp=explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']);
        $onlineip = $ip_temp[0];

这样子做有一个BUG:如果访问者用内网代理,得到的IP将会是内网IP。我正在想办法解决。

最后,要做的就是解决后台操作非法的问题。由于有我前面说的那个BUG,我不建议修改这个,可以说明的就是修改的方法跟前台类似。