Tomcat负载均衡原理详解及配置

Tomcat负载均衡原理详解及配置(Apache2.2.19+Tomcat7.0.12)

转自http://www.cnblogs.com/leader_89/archive/2011/08/01/2109181.html

结构图

使用Tomcat的童鞋们注意了。为了增加tomcat的性能和稳定性,我们一般采用balance和session同步机制。 下图列出了我们常用也是最简单的解决方案。

说明

1 balance

1.1 mod_proxy方式

  mod_proxy是一种分工合作的的形式,通过主服务器跳转到各台主机负责不同的任务而实现任务分工,这种形式不能实现负载均衡,只能提供主服务器的访问跳转
  修改apache的httpd.conf文件配置

打开httpd.conf文件,取消下面四行的注释,用以打开代理所需的.so支持模块。

View Code

打开文件conf\extra\httpd-vhosts.conf,可以看到如下代码:

View Code

根据需要更改<VirtualHost>节点内的参数。

说明:NameVirtualHost *:80和<VirtualHost *:80>中 的*为当前服务器IP,如果有固定IP可以用IP把*替换掉,我这里使用的是动态IP,所以用*,我看apache帮助文档的时候,一直认为这里的*为对 应的域名,这个想法应该是错误的,因为我填上域名的时候一直没有设置成功。ServerName这个填域名,DocumentRoot填 ServerName上域名对应的根目录。

注:

如果访问域名出现403权限错误,且对应的文件夹everyone的权限都是全部控制,则问题出在httpd.conf上。 
编辑httpd.conf,找到DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"这项,这是默认根目录路径,但是要更改的不是这个,一直往下找,找到<Directory />节点,然后在节点结束后加上:
View Code

这里的"C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host.leader89"和"C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host2.leader89"为前面VirtualHost里的路径。 
保存httpd.conf和httpd-vhosts.conf,然后重启Apache。 
然 后访问dummy-host.leader89打开的是C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host.leader89目录,
访问dummy-host2.leader89的是C:/Program Files/Apache Software Foundation/Apache2.2/docs/dummy-host2.leader89目录,
实现了单IP多域名多站点的功能。

1.2 mod_proxy_blancer方式

  mod_proxy_balancer是mod_proxy的扩展,提供负载平衡支持,通过mod_proxy_balancer.so包实现负载平衡,公司生产服务器暂时就采用这种方式。
  修改apache的httpd.conf文件配置

打开httpd.conf文件,取消下面四行的注释,用以打开代理所需的.so支持模块。

View Code

在httpd.conf文件最后添加以下代码:

View Code

将下载的tomcat压缩包解压两份,分别命名为tomcat1、tomcat2。修改tomcat2中conf/server.xml中部分端口号(因为我在本机做测试,所以为了解决端口号被占用的问题修改tomcat2的端口号,使tomcat1与tomcat2能够同时启动,实现多服务器;如果有多台PC服务器可不必修改),修改内容如下:

View Code

1)轮询均衡策略的配置

ProxyPass / balancer://proxy/
<
Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/
BalancerMember http://127.0.0.1:8081/
</Proxy>
实现负载均衡的原理如下:

假设Apache接收到http://localhost/test请求,由于该请求满足ProxyPass条件(其URL前缀为“/"),该请求会 被分发到后台某一个BalancerMember,譬如,该请求可能会转发到http://127.0.0.1:8080/进行处理?当第二 个满足条件的URL请求过来时,该请求可能会被分发到另外一台BalancerMember,譬如,可能会转发到 http://127.0.0.1:8081/如此循环反复,便实现了负载均衡的机制?

2)按权重分配均衡策略的配置

ProxyPass / balancer://proxy/
<
Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/ loadfactor=3
BalancerMember http://127.0.0.1:8081/ loadfactor=1
</Proxy>

参数"loadfactor"表示后台服务器负载到由Apache发送请求的权值,该值默认为1,可以将该值设置为1到100之间的任何值?以上面 的配置为例,介绍如何实现按权重分配的负载均衡,现假设Apache收到http://myserver/test 4次这样的请求,该请求分别被负载到后台 服务器,则有3次连续的这样请求被负载到BalancerMember为http://127.0.0.1:8080/的服务器,有1次这样的请求被 负载BalancerMember为http://127.0.0.1:8081/后台服务器?实现了按照权重连续分配的均衡策略?

3)权重请求响应负载均衡策略的配置

ProxyPass / balancer://proxy/ lbmethod=bytraffic
<
Proxy balancer://proxy>
BalancerMember http://127.0.0.1:8080/ loadfactor=3
BalancerMember http://127.0.0.1:8081/ loadfactor=1
</Proxy>

参数“lbmethod=bytraffic"表示后台服务器负载请求和响应的字节数,处理字节数的多少是以权值的方式来表示的? “loadfactor"表示后台服务器处理负载请求和响应字节数的权值,该值默认为1,可以将该值设置在1到100的任何值?根据以上配置是这么进行均 衡负载的,假设Apache接收到http://myserver/test请求,将请求转发给后台服务器,如果BalancerMember为http://127.0.0.1:8080/后台服务器负载到这个请求,那么它处理请求和响应的字节数是BalancerMember为http://127.0.0.1:8081/服务器的3倍(回想(2)均衡配置,(2)是以请求数作为权重负载均衡的,(3)是以流量为权重负载均衡的,这是 最大的区别)?

至此配置以完成

  在tomcat1中webapps文件夹下新建test项目文件夹,test目录下新建如下页面

View Code

如需session复制功能此步骤为必须操作

  打开项目的WEB-INF下的web.xml在</web-app>内添加<distributable/>标签,如果没有则手动建立目录结构

View Code

将tomcat1下的test项目复制一份到tomcat2的webapps目录下
至此所有操作已完成 

启动tomcat1、tomcat2、apache。打开浏览器,输入http://localhost/test/test.jsp回车,刷新几次即可从tomcat1与tomcat2的控制台看到负载效果。输入session即可看到session复制效果

1.3 mod_jk方案
mod_jk是比较专门针对Tomcat的方法,通过AJP协议连接Tomcat
1)需要下载mod_jk-1.2.31-httpd-2.2.3.so    http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.31/mod_jk-1.2.31-httpd-  2.2.3.so包并放到Apache安装目录下的modules子目录中
2)然后配置mod_jk.conf
3)配置workers2.properties
注意:因为mod_jk2方式不被推荐,mod_jk2已经不再被更新了。因此,此处不予列举,如有需要参考者请留言,将随后贴出。

 proxy、proxy_blancer和mod_jk的比较

  • proxy的缺点是,当其中一台tomcat停止运行的时候,apache仍然会转发请求过去,导致502网关错误。但是只要服务器再启动就不存在这个问题。
  • mod_jk方式的优点是,Apache 会自动检测到停止掉的tomcat,然后不再发请求过去。
    缺点就是,当停止掉的tomcat服务器再次启动的时候,Apache检测不到,仍然不会转发请求过去。
  • proxy和mod_jk的共同优点是.可以只将Apache置于公网,节省公网IP地址资源。
    可以通过设置来实现Apache专门负责处理静态网页,让Tomcat专门负责处理jsp和servlet等动态请求。
    共同缺点是:如果前置Apache代理服务器停止运行,所有集群服务将无法对外提供。
  • proxy和mod_jk对静态页面请求的处理,都可以通设置来选取一个尽可能优化的效果。
    mod_proxy_balancer和mod_jk都需要修改tomcat的配置文件配合
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
  • 这三种Tomcat集群方式对实现最佳负载均衡都有一定不足,mod_proxy_balancer和mod_jk相对好些,mod_jk的设置能力更强些。lbfactor参数来分配请求任务。
  • apache自带mod_proxy功能模块中目前只可以实现两种不同的负载均衡集群实现方式,第一种是分工合作的的形式,通过各台主机负责不同的任务而实 现任务分工。第二种是不同的机器在担任同样的任务,某台机器出现故障主机可以自动检测到将不会影响到客户端,而第一种却不能实现但第一种实现方式的优点在 于他是主服务器负担相应没第二种大因为台只是提供跳转指路功能,形象的说他不给你带路只是告诉你有条路可以到,但到了那是否可以看到你见的人他已经不会去管你了。相比之下第二种性能要比第一种会好很多;但他们都有个共同点都是一托N形式来完成任务的所以你的主机性能一定要好。

2 session同步

  • 对于tomcat的集群有两种方式,这个主要是针对session而言的。一种就是sticky模式,即黏性会话模式;另外一种就是session复制模式了。

2.1 sticky模式

  • 利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的Tomcat节点。这样不同用户的请求就被平均分配到集群 中各个tomcat节点上,实现负载均衡的能力。这样做的缺点是没有灾难恢复的能力。一旦一个节点发生故障,这个节点上所有的session信息全部丢 失;
  • 这种方式其实是由前端balancer实现的,基本不需要webServer做任何改动(只需要修改jvmRoute="tomcat1")
  • 同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用

2.2 复制模式

  • 利用Tomcat session复制的机制使得所有session在所有Tomcat节点中保持一致。当一个节点修改一个session数据的时候,该节点会把这个 session的所有内容序列化,然后广播给所有其它节点。这样当下一个用户请求被负载均衡器分配到另外一个节点的时候,那个节点上有完备的 session信息可以用来服务该请求。这种做法的问题是对session哪怕有一点点修改,也要把整个sessions数据全部序列化 (serialize),还要广播给集群中所有节点,不管该节点到底需不需要这个session。这样很容易会造成大量的网络通信,导致网络阻塞。一般采 用这种方式,当Tomcat节点超过4个时候,整个集群的吞吐量就不能再上升了;
  • 此方式是通过tomcat本身提供的功能,只需要修改server.xml文件
    (1)修改Engine节点信息: <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
    (2)去掉<Cluster> <\Cluster> 的注释符
    (3)web.xml中增加 <distributable/>

2.3 Terracotta模式

  • 另一种方式就是利用开源软件Terracotta。Terracotta的基本原理是对于集群间共享的数据,当在一个节点发生变化的时 候,Terracotta只把变化的部分发送给Terracotta服务器,然后由服务器把它转发给真正需要这个数据的节点。这样对网络的压力就非常小, 各个节点也不必浪费CPU时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在session同步上,相当于对tomcat第二种集群实现 机制进行了优化,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果。在对比测试中,采用Terracotta搭建Tomcat集群,节点达到8 个时候,整个集群的吞吐量还一直是线性增长的。

2.4 三种模式比较

  • sticky模式最大的缺点就是不支持failover,一旦某一个webServer发生故障则此节点上的session就会丢失,因此不建议使用。
  • 复制模式可以保证个别节点发生故障不丢失session,但是复制时需要序列化数据这会影响到系统的性能。
    另外性能随着服务器增加急剧下降,而且容易引起广播风暴。经测试当Tomcat节点超过4个时候,整个集群的吞吐量就不能再上升了。
    需要修改server.xml和web.xml文件
  • 使用第三方软件Terracotta进行session同步,配置对原来的web应用完全透明,原有程序不用做任何修改。。
    数据不需要序列化,也不占用webServer的内存,执行效率高。
  • terracotta本身支持HA,增加了系统的稳定性。
  • Terracotta是开源的,并且可以集成在很多主流的开源软件中,如Jetty、Tomcat、Spring、Geronimo和EHCache等。





Apache+Tomcat实现负载均衡

反向代理负载均衡 (Apache2+Tomcat7/8) 
使用代理服务器可以将请求转发给内部的Web服务器,让代理服务器将请求均匀地转发给多台内部Web服务器之一上,从而达到负载均衡的目的。这种代理方式与普通的代理方式有所不同,标准代理方式是客户使用代理访问多个外部Web服务器,而这种代理方式是多个客户使用它访问内部Web服务器,因此也被称为反向代理模式。 

此次使用的代理为mod_proxy的方式来实现的,因为在Apache2以上的版本中已经集成了,因此不需要再另行安装和配置了,只需要把注释去掉即可,此去掉的配置,个人感觉与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  #让代理服务器能支持HTTP协议

然后把:

#Include conf/extra/httpd-vhosts.conf的注释也去掉,配置的负载均衡

具体配置如下:

复制代码
#虚拟机配置,负载均衡配置  注意空格
<VirtualHost *:9999>
    ServerAdmin binbin@locahost
    ServerName localhost
    ServerAlias localhost
    ProxyPass / balancer://cluster/ stickysession=JSESSIONID|jsessionid nofailover=On
    ProxyPassReverse / balancer://cluster/
    #ErrorLog "logs/error.log"
    #CustomLog "logs/access.log" common
</VirtualHost> 

#The ProxyRequests directive should usually be set off when using ProxyPass.
ProxyRequests Off
<proxy balancer://cluster>
    BalancerMember ajp://localhost:8009 loadfactor=1 route=tomcat8_local  smax=5 max=20 ttl=120 retry=300 timeout=15
    BalancerMember ajp://192.168.1.250:8009 loadfactor=1 route=tomcat8_250  smax=5 max=20 ttl=120 retry=300 timeout=15
        ProxySet lbmethod=byrequests
</proxy>
复制代码

其中:  localhost:8009 和  192.168.1.250:8009为两个负载均衡服务器
 loadfactor=1 route=tomcat8_local  smax=5 max=20 ttl=120 retry=300 timeout=15 这个为配置的参数,最大链接,超时,等等

route=tomcat8_local  可以不写

ProxySet lbmethod=byrequests 为实现负载均衡的方式,共有三种类型

#lbmethod=byrequests 按照请求次数均衡(默认) 
#lbmethod=bytraffic 按照流量均衡 
#lbmethod=bybusyness 按照繁忙程度均衡(总是分配给活跃请求数最少的服务器)

route=tomcat8_local  根据这个route的值,分别在两个Tomat中的Service.xml的   Engine 节点配置上jvmRoute的内容,如下: <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat8_local">和以及jvmRoute="tomcat8_250" ,不过我在测试是,感觉如果不配置,也不会影响程序的执行。

启动以上程序就可以进行测试了,测试页面来源于网络:

复制代码
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster Test</title></head>
<body>
<%
  //HttpSession session = request.getSession(true);
  System.out.println(session.getId());
  out.println("<br> SESSION ID:" + session.getId()+"<br>");  
  // 如果有新的请求,则添加session属性
  String name = request.getParameter("name");
  if (name != null && name.length() > 0) {
     String value = request.getParameter("value");
     session.setAttribute(name, value);
  }  
    out.print("<b>Session List:</b>");  
    Enumeration<String> names = session.getAttributeNames();
    while (names.hasMoreElements()) {
        String sname = names.nextElement(); 
        String value = session.getAttribute(sname).toString();
        out.println( sname + " = " + value+"<br>");
        System.out.println( sname + " = " + value);
   }
%>
  <form action="testCluster.jsp" method="post">
    名称:<input type=text size=20 name="name">
     <br>
    值:<input type=text size=20 name="value">
     <br>
    <input type=submit value="提交">
   </form>

   <b>负载均衡测试:此为:Tomcat7_a上的文件,<font color=red>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</font><b>
</body>
</html>
复制代码

复制代码
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster Test</title></head>
<body>
<%
  //HttpSession session = request.getSession(true);
  System.out.println(session.getId());
  out.println("<br> SESSION ID:" + session.getId()+"<br>");  
  // 如果有新的请求,则添加session属性
  String name = request.getParameter("name");
  if (name != null && name.length() > 0) {
     String value = request.getParameter("value");
     session.setAttribute(name, value);
  }  
    out.print("<b>Session List:</b>");  
    Enumeration<String> names = session.getAttributeNames();
    while (names.hasMoreElements()) {
        String sname = names.nextElement(); 
        String value = session.getAttribute(sname).toString();
        out.println( sname + " = " + value+"<br>");
        System.out.println( sname + " = " + value);
   }
%>
  <form action="testCluster.jsp" method="post">
    名称:<input type=text size=20 name="name">
     <br>
    值:<input type=text size=20 name="value">
     <br>
    <input type=submit value="提交">
   </form>

   <b>负载均衡测试:此为:Tomcat7_a上的文件,<font color=red>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</font><b>
</body>
</html>
复制代码

此时访问就会再个不同的页面了,一个为aaaaaaaaaaaaaaaaaaaaaaaaaaaa 一个为bbbbbbbbbbbbbbbbbbbbbbbbbbb;

如下图所示:

看到的两个Session的值不同,因为这里还没有session的共享配置

注意:

以上仅仅实现了负载均衡,但是对于两个负载同时宕机的话,就需要另外的一台服务器来代替了,这第n+1台服务器就叫热备服务器,配置方式与以上相同,仅需要写上status=+H 标识即可。

BalancerMember http://192.168.1.218:8009 status=+H

以上负载均衡就算全部完成了,如果要实现Session共享,最简单的方式就是在Tomcat中进行配置,配置如下:

在 service.xml文件中的 Engine节点,添加如下代码:

复制代码
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">
                  <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>

          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4001"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>

            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>
  </Cluster> 
复制代码

 


  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值