Apache+Tomcat负载均衡(一):mod_proxy

所有博文均在个人独立博客http://blog.mozhu.org首发,欢迎访问!

环境准备

Apache版本:2.4.18
下载地址:http://httpd.apache.org/download.cgi

Tomcat版本:6.0.44
下载地址:
http://tomcat.apache.org/download-60.cgi

JDK:1.6
OS:Windows 7 x64

安装Apache和Tomcat

解压Apache到D:/Apache目录,后文以APACHE_HOME替代该目录
解压Tomcat到D:/TomcatTest目录,即:D:/TomcatTest/tomcat,后文以TOMCAT_HOME替代该目录

TOMCAT_HOME/bin目录下添加setenv.bat文件加入

1
set JAVA_OPTS=%JAVA_OPTS% -Dserver=1

注:该server的值会在后面jsp页面中System.getProperty(“server”)取到

将tomcat复制三份,分别为:
D:/TomcatTest/tomcat1
D:/TomcatTest/tomcat2
D:/TomcatTest/tomcat3

修改三个Tomcat中conf/server.xml的Http端口(默认8080)及AJP13(默认8009)端口配置,防止端口冲突

1
2
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Tomcat http端口 AJP13端口
tomcat1 9091 8019
tomcat2 9092 8029
tomcat3 9093 8039

修改三个Tomcat中bin/setenv.bat中的server标志
tomcat1:

1
set JAVA_OPTS=%JAVA_OPTS% -Dserver=1

tomcat2:

1
set JAVA_OPTS=%JAVA_OPTS% -Dserver=2

tomcat3:

1
set JAVA_OPTS=%JAVA_OPTS% -Dserver=3

将WebDemo.war解压在D:/TomcatTest/webapps目录下
修改TOMCAT_HOME/conf/server.xml
节点内添加

1
<Context path="/WebDemo" docBase="D:\TomcatTest\webapps\WebDemo" reloadable="true"/>

index.jsp源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
String server = System.getProperty("server");
request.setAttribute("Server", server);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
request.setAttribute("CurrentTime", dateFormat.format(new Date()));
%>
<html>
Current Server: ${Server} <br/>
Current Time: ${CurrentTime} <br/>
</html>

分别启动三个Tomcat,并访问WebDemo应用
访问http://localhost:9091/WebDemo/index.jsp
看到下面
Current Server: 1
Current Time: 2015-12-31 15:49:31

mod_proxy方式

从apache2.2以后官方自带mod_proxy,不用再下载额外的module包了,配置起来也很方便
修改APACHE_HOME/conf/httpd.conf
添加一行

1
Include conf/extra/httpd-proxy.conf

httpd-proxy.conf内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so

<Proxy balancer://mycluster>
BalancerMember http://127.0.0.1:9091
BalancerMember http://127.0.0.1:9092
BalancerMember http://127.0.0.1:9093
ProxySet lbmethod=bytraffic
</Proxy>
ProxyRequests Off
ProxyPass /test balancer://mycluster/
ProxyPassReverse /test balancer://mycluster/

启动apache

1
httpd -k start

打开浏览器访问:
http://localhost/test/WebDemo/index.jsp
不断刷新,可以看到
Current Server: 1
不断从1-3变化,则表明,负载均衡配置成功

loadfactor参数设置:
服务器的权重进行负载均衡了,权重大的表示服务器处理能力强,可以处理更多的请求


BalancerMember http://127.0.0.1:9091 loadfactor=1
BalancerMember http://127.0.0.1:9092 loadfactor=2
BalancerMember http://127.0.0.1:9093 loadfactor=3
ProxySet lbmethod=bytraffic

修改配置如上并重启apache,重复刷新页面,可以看到
Current Server: 1
第1次刷新会看到Current Server: 1
第2次刷新会看到Current Server: 2
第3次刷新会看到Current Server: 2
第4次刷新会看到Current Server: 3
第5次刷新会看到Current Server: 3
第6次刷新会看到Current Server: 3
这样apache就可以按照服务器的权重进行负载均衡了,权重大的表示服务器处理能力强,可以处理更多的请求

lbmethod参数设置
lbmethod表示负载载均衡策略。
lbmethod=byrequests 按照请求次数均衡(默认)
lbmethod=bytraffic 按照流量均衡
lbmethod=bybusyness 按照繁忙程度均衡(总是分配给活跃请求数最少的服务器)
当需要开启这些负载均衡策略时,需要分别加载如下module:
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so

热备(Hot Standby)
热备份的实现很简单,只需添加 status=+H 属性,就可以把某台服务器指定为备份服务器

BalancerMember http://127.0.0.1:9091 loadfactor=1 status=+H
BalancerMember http://127.0.0.1:9092 loadfactor=1
BalancerMember http://127.0.0.1:9093 loadfactor=1
ProxySet lbmethod=bytraffic

在tomcat1的BalancerMember后加上status=+H则可以把tomcat1当成热备机器,在tomcat2,和tomcat3正常运行期间,apache不会将请求转发到tomcat1上,如果tomcat2,和tomcat3同时宕机,则请求会转发到tomcat1上,当tomcat2,和tomcat3再次恢复工作时,请求会重新转发到tomcat2,和tomcat3上。

lbset参数设置
类似于在balancerMember中建立群组的概念,lbset值越低,优先级越高,apache优先将请求转发到lbset更低的balancerMember上,当这组balancerMember都宕机的话,才会将请求分发到其他组的balancerMember上

BalancerMember http://127.0.0.1:9091 loadfactor=1 lbset=2
BalancerMember http://127.0.0.1:9092 loadfactor=1 lbset=1
BalancerMember http://127.0.0.1:9093 loadfactor=1 lbset=1
ProxySet lbmethod=bytraffic

修改配置如上并重启apache
打开浏览器访问:
http://localhost/test/WebDemo/index.jsp
不断刷新,发现apache只能将请求转到后台的tomcat2,和tomcat3上,我们手动关闭tomcat2,和tomcat3后,请求才转到tomcat1上
重新启动tomcat2,和tomcat3,等大约1分钟左右,新的请求又会重新转发到tomcat2,和tomcat3上,不难发现这种配置和将tomcat1变成热备(status=+H)的配置功能有同样的效果。

route参数设置
如果只用到最基本的负载均衡,route是可以不用设置的,如果需要配置tomcat做StickySession的话,需要设置该值,和后台Tomcat中server.xml中Engine节点中jvmRoute值保持一致

BalancerMember http://127.0.0.1:9091 loadfactor=1 route=tomcat1
BalancerMember http://127.0.0.1:9092 loadfactor=1 route=tomcat2
BalancerMember http://127.0.0.1:9093 loadfactor=1 route=tomcat3
ProxySet lbmethod=bytraffic

关于ProxyPassReverse
在httpd-proxy.conf的配置中,有如下反向代理设置
ProxyPass /test balancer://mycluster/
ProxyPassReverse /test balancer://mycluster/
ProxyPass 很好理解,就是把所有来自客户端对/test的请求转发给balancer://mycluster/上定义的tomcat上进行处理。
ProxyPassReverse 的配置总是和ProxyPass 一致,但用途很让人费解,似乎去掉它很能很好的工作。
事实真的是这样么?其实不然,如果响应中有302重定向,ProxyPassReverse就派上用场。
我们可以写一个例子来测试下:
redirect.jsp:
<%@ page language=”java” contentType=”text/html; charset=UTF-8” pageEncoding=”UTF-8”%>
<% response.sendRedirect(“welcome.jsp”); %>

welcome.jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8” pageEncoding=”UTF-8”%>
welcome

我们注释掉ProxyPassReverse

#ProxyPassReverse /test balancer://mycluster/
重启Apache,然后访问
http://localhost/test/WebDemo/redirect.jsp
页面会跳转到
http://127.0.0.1:9092/test/WebDemo/welcome.jsp

mod_proxy_1

如果没有配置反向代理(ProxyPassReverse),客户端收到的请求响应是重定向操作,并且重定向目的url为http://127.0.0.1:9092/test/WebDemo/welcome.jsp ,而这个地址如果只是代理服务器能访问到的(目前例子里是可以绕过apache直接访问到tomcat后的url资源),可想而知,客户端肯定是打不开的。反之如果配置了反向代理,则会在转交HTTP重定向应答到客户端之前调整它为http://localhost/test/WebDemo/welcome.jsp。

我们取消注释ProxyPassReverse
ProxyPassReverse /test balancer://mycluster/
重启Apache,然后访问
http://localhost/test/WebDemo/redirect.jsp
页面会跳转到
http://localhost/test/WebDemo/welcome.jsp

查看Chrome控制台,可以看到,这时,apache会将原本响应头里的http://127.0.0.1:9092/test/WebDemo/welcome.jsp

Localtion:http://127.0.0.1:9092/test/WebDemo/welcome.jsp
变成了:
Localtion:http://localhost/test/WebDemo/welcome.jsp

Apache还可以通过AJP13协议和后台Tomcat进行连接
只要修改httpd-proxy.conf(需要加载proxy_ajp_module)
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so


BalancerMember ajp://127.0.0.1:8019 loadfactor=1 route=tomcat1
BalancerMember ajp://127.0.0.1:8029 loadfactor=1 route=tomcat2
BalancerMember ajp://127.0.0.1:8039 loadfactor=1 route=tomcat3
ProxySet lbmethod=bytraffic

ProxyRequests Off
ProxyPass /test balancer://mycluster/

重启apache,打开浏览器访问:
http://localhost/test/WebDemo/index.jsp
不断刷新,可以看到
Current Server: 1
不断从1-3变化,则表明,apache通过AJP连接Tomcat负载均衡配置成功

AJP 模式下ProxyPassReverse不起作用,页面有redirect时不能正常跳转
官方解释,请参考页面:
https://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html
However, it is usually better to deploy the application on the backend server at the same path as the proxy rather than to take this approach.
官方建议,在AJP协议下,apache暴露的访问路径最好和后台的路径一致,否则AJP模式下redirect会失效,也就是说,如果我们后台应用是/,通过apache暴露出去的最好也是/而不是/test
我们可以访问
http://localhost/test/WebDemo/redirect.jsp
页面会跳转到
http://localhost/WebDemo/welcome.jsp
很显然跳转失败

修改反向代理设置,将/test改为/
ProxyPass / balancer://mycluster/
重启apache
我们可以访问
http://localhost/WebDemo/redirect.jsp
页面会跳转到
http://localhost/WebDemo/welcome.jsp
这样跳转就成功了

集群监控
在配置文件/conf/extra/httpd-proxy.conf中加入


SetHandler balancer-manager
Require all granted


SetHandler server-status
Require all granted


SetHandler server-info
Require all granted

配置完成后重启Apache可以通过
http://localhost/server-staus
http://localhost/server-info
http://localhost/balancer-manager
这些URL查看apache 集群的运行状态
其中server-status可以查看服务器运行状态;
server-info可以查看服务器配置信息;
balancer-manager可以管理集群,修改负载均衡配置,动态生效(修改后的配置不会保存,重启后失效)

注意:
1.文中所有Require all granted的地方因为为了测试方便,均采用此配置,表示这些权限对多有人开放,如果要应用于生产环境,请务必修改,防止服务器信息被泄露或集群配置被恶意修改。
2.文中所有Require all granted的地方均为apache2.4的配置方式,若使用apache2.2,请自行修改为相应的配置方式。

参考链接:
mod_proxy
http://httpd.apache.org/docs/2.2/en/mod/mod_proxy.html

mod_proxy_balancer算法
http://httpd.apache.org/docs/2.2/en/mod/mod_proxy_balancer.html

Apache2.2和Apache2.4中httpd.conf配置文件的异同
http://www.upupw.net/server/n75.html

分享到