Tomcat集群Cluster实现原理剖析

在上一篇文章中简要介绍了如何通过简单的配置来实现tomcat集群,本文意在介绍对tomcat集群进行更深入详细的配置以满足特定需求。

 

     对于WEB应用集群的技术实现而言,最大的难点就是如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块。

    要实现这一点,大体上有两种方式,

          一种是把所有Session数据放到一台服务器上或者数据库中,集群中的所有节点通过访问这台Session服务器来获取数据;

          另一种就是在集群中的所有节点间进行Session数据的同步拷贝,任何一个节点均保存了所有的Session数据。

   两种方式都各有优点,

         第一种方式简单、易于实现,但是存在着Session服务器发生故障会导致全系统不能正常工作的风险;

         第二种方式可靠性更高,任一节点的故障不会对整个系统对客户访问的响应产生影响,但是技术实现上更复杂一些。

 

    常见的平台或中间件如microsoft asp.net和IBM WAS都会提供对两种共享方式的支持,tomcat也是这样,但是一般采用第二种方式。

 

     当采用tomcat默认集群配置(<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>)时,配置的细节实际上被省略了,

    对于大多数应用而言,使用默认配置已经足够,完整的默认配置应该是这样:

 

     <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="4000"
                      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"/>
          <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster> 

 

     下面笔者对这里的配置项作详细解释,以下内容均是笔者阅读了tomcat官方文档后自己的理解,有些可能不对,希望读者能带着批判的眼光阅读,并欢迎指正笔者错误。

 

     tomcat集群各节点通过建立tcp链接来完成Session的拷贝,拷贝有同步和异步两种模式。

     在同步模式下,对客户端的响应必须在Session拷贝到其他节点完成后进行;

     异步模式无需等待Session拷贝完成就可响应。

 

     异步模式更高效,但是同步模式可靠性更高。同步异步模式由channelSendOptions参数控制,默认值是8,为异步模式,4是同步模式。

    在异步模式下,可以通过加上拷贝确认(Acknowledge)来提高可靠性,此时channelSendOptions设为10。

 

     Manager用来在节点间拷贝Session,默认使用DeltaManager,DeltaManager采用的一种all-to-all的工作方式,

     即集群中的节点会把Session数据向所有其他节点拷贝,而不管其他节点是否部署了当前应用。

     当集群中的节点数量很多并且部署着不同应用时,可以使用BackupManager,BackManager仅向部署了当前应用的节点拷贝Session。

     但是到目前为止BackupManager并未经过大规模测试,可靠性不及DeltaManager。

 

     Channel负责对tomcat集群的IO层进行配置。Membership用于发现集群中的其他节点,

     这里的address用的是组播地址(Multicast address,了解更多组播地址详情请参见http://zyycaesar.iteye.com/admin/blogs/296501),

     使用同一个组播地址和端口的多个节点同属一个子集群,因此通过自定义组播地址和端口就可将一个大的tomcat集群分成多个子集群。

     Receiver用于各个节点接收其他节点发送的数据,在默认配置下tomcat会从4000-4100间依次选取一个可用的端口进行接收,

     自定义配置时, 如果多个tomcat节点在一台物理服务器上注意要使用不同的端口。

 

     Sender用于向其他节点发送数据,具体实现通过Transport配置,

     PooledParallelSender是从tcp连接池中获取连接,可以实现并行发送,即集群中的多个节点可以同时向其他所有节点发送数据而互不影响。

     Interceptor有点类似下面将要解释的Valve,起到一个阀门的作用,在数据到达目的节点前进行检测或其他操作,如TcpFailureDetector用于检测在数据的传输过程中是否发生了tcp错误。

     关于Channel的编程模型,请参见http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/tribes/Channel.html

 

     Valve用于在节点向客户端响应前进行检测或进行某些操作,

     ReplicationValve就是用于用于检测当前的响应是否涉及Session数据的更新,如果是则启动Session拷贝操作,filter用于过滤请求,如客户端对图片,css,js的请求就不会涉及Session,

     因此不需检测,默认状态下不进行过滤,监测所有的响应。

    JvmRouteBinderValve会在前端的Apache mod_jk发生错误时保证同一客户端的请求发送到集群的同一个节点,

    tomcat官方文档并未解释如何实现这一点,而且笔者认为这一设置似乎并无多大实用性。

 

     Deployer用于集群的farm功能,监控应用中文件的更新,以保证集群中所有节点应用的一致性,

     如某个用户上传文件到集群中某个节点的应用程序目录下,Deployer会监测到这一操作并把这一文件拷贝到集群中其他节点相同应用的对应目录下以保持所有应用的一致。

     这是一个相当强大的功能,不过很遗憾,tomcat集群目前并不能做到这一点,开发人员正在努力实现它,这里的配置只是预留了一个接口。

 

    Listener用于跟踪集群中节点发出和收到的数据,也有点类似Valve的功能。

 

    在大体了解了tomcat集群实现模型后,就可以对集群作出更优化的配置了,

    tomcat推荐了一套配置,使用了比DeltaManager更高效的BackupManager,并且对ReplicationValve设置了请求过滤,

    注意在一台服务器部署多个节点时需要修改Receiver的侦听端口,另外,为了更高效的在节点间拷贝数据,所有tomcat节点最好采用相同的配置,

   具体配置如下:

     <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"  channelSendOptions="6">
          <Manager className="org.apache.catalina.ha.session.BackupManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"
                   mapSendOptions="6"/>
          <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="5000"
                      selectorTimeout="100"
                      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"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
          </Channel>
          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>

 

     Tomcat集群除了可以进行Session数据的拷贝,还可进行Context属性的拷贝,通过修改context.xml的Context配置可以实现,

     使用<Context className="org.apache.catalina.ha.context.ReplicatedContext"/>替换默认Context即可,当然也可再加上distributable="true"属性。

 

     下面通过假想的一组场景来描述tomcat集群如何工作,集群采用默认配置,由t1和t2两个tomcat例程组成,场景按照时间顺序排列。

1. t1启动

     t1按照标准的tomcat启动,当Host对象被创建时,一个Cluster对象(默认配置下是SimpleTcpCluster)也同时被关联到这个Host对象。

    当某个应用在web.xml中设置了distributable时,Tomcat将为此应用的上下文环境创建一个DeltaManager。

    SimpleTcpCluster启动membership服务和Replication服务(用于建立tcp连接)。

2. t2启动(待t1启动完成后)
     首先t2会执行和t1一样的操作,然后SimpleTcpCluster会建立一个由t1和t2组成的membership。

    接着t2向集群中已启动的服务器即t1请求Session数据,如果t1没有响应t2的拷贝请求,t2会在60秒后time out。

    在Session数据拷贝完成之前t2不会接收客户端的http或mod_jk/ajp请求。

3. t1接收http请求,创建Session s1
     t1正常响应客户请求,但是在t1把结果发送回客户端时,ReplicationValve会拦截当前请求(如果filter中配置了不需拦截的请求类型,这一步就不会进行,默认配置下拦截所有请求),

    如果发现当前请求更新了Session,调用Replication服务建立tcp连接把Session拷贝到membership列表中的其他节点即t2,

    返回结果给客户端(注意,如果采用同步拷贝,必须等拷贝完成后才会返回结果,异步拷贝在数据发送到tcp连接就返回结果,不等待拷贝完成)。

    在拷贝时,所有保存在当前Session中的可序列化的对象都会被拷贝,而不仅仅是发生更新的部分。

4. t1崩溃
     当t1崩溃时,t2会被告知t1已从集群中退出,然后t2就会把t1从自己的membership列表中删除,

    发生在t2的Session更新不再往t1拷贝,同时负载均衡器会把后续的http请求全部转发给t2。

    在此过程中所有的Session数据不会丢失。

5. t2接收s1的请求
     t2正常响应s1的请求,因为t2保存着s1的所有数据。

6. t1重新启动
     按步骤1、2一样的操作启动,加入集群,从t2拷贝所有Session数据,拷贝完成后开放自己的http和mod_jk/ajp端口接收请求。

7. t1接收请求,s1失效
     t1继续接收来自s1的请求,把s1设置为过期。

    这里的过期并非因为s1处于非活动状态超过设置的时间,而是执行类似注销的操作而引起的Session失效。

    这时t1并非发送s1的所有数据而是一个类似s1 expired的消息,t2收到消息后也会把s1设为过期。

8. t2接收请求,创建Session s2
     和步骤3一样。

9. t1 s2过期
     对于因超时引起的Session失效t1无需通知t2,因为t2同样知道s2已经超时。

    因此对于tomcat集群有一点非常重要,所有节点的操作系统时间必须一致!

   不然会出现某个节点Session已过期而在另一节点此Session仍处于活动状态的现象。

 

 

 

因为tomcat的session同步功能需要用到组播,

windows默认情况下是开通组播服务的,

但是linux默认情况下并没有开通,

可以通过指令打开route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0,

如果需要服务器启动时即开通组播需在/etc/sysconfig/static-routes文件内加入

eht0 net 224.0.0.0 netmask 240.0.0.0。

原文:http://zhumeng8337797.blog.163.com/blog/static/100768914201182393913305/

时间: 2024-11-08 18:28:15

Tomcat集群Cluster实现原理剖析的相关文章

tomcat集群机制剖析及其生产部署选型

为什么要使用集群? 为什么要使用集群?主要有两方面原因:一是对于一些核心系统要求长期不能中断服务,为了提供高可用性我们需要由多台机器组成的集群:另外一方面,随着访问量越来越大且业务逻辑越来越复杂,单台机器的处理能力已经不足以处理如此多且复杂的逻辑,于是需要增加若干台机器使整个服务处理能力得到提升. 集群难点在哪? 如果说一个web应用不涉及会话的话,那么做集群是相当简单的,因为节点都是无状态的,集群内各个节点无需互相通信,只需要将各个请求均匀分配到集群节点即可.但基本所有web应用都会使用会话机

tomcat集群实现源码级别剖析

随着互联网快速发展,各种各样供外部访问的系统越来越多且访问量越来越大,以前Web容器可以包揽接收-逻辑处理-响应整个请求生命周期的工作,现在为了构建让更多用户访问更强大的系统,人们通过不断地业务解耦.架构解耦将web容器的逻辑处理抽离交由其他中间件处理,例如缓存中间件.消息队列中间件.数据存储中间件等等.Web容器负责的工作可能越来越少,但是它确实必不可少的部分,它负责接收用户请求并分别调用各个服务最后响应.可以说目前最受欢迎的web容器是用Java写的tomcat小猫,由于生产上的tomcat

Tomcat集群如何同步会话

Tocmat集群中最重要的交换信息就是会话消息,对某个tomcat实例某会话做的更改要同步到集群其他tomcat实例的该会话对象,这样才能保证集群所有实例的会话数据一致.在tribes组件的基础上完成这些工作就相当容易些,tribes是tomcat实现的一个通信框架. 如下图,tomcat实现会话同步的过程中大致会使用如下组件,现在假设中间的tomcat实例的会话改变了,它会通过会话管理器Manager将改变的动作消息封装成消息然后调用集群对象Cluster,通过Cluster将消息发送出去,同

Tomcat集群应用部署的实现机制

集群应用部署是一个很重要的应用场景,设想一下如果没有集群应用部署功能,每当我们发布应用时都要登陆每台机器对每个tomcat实例进行部署,这些工作量都是繁杂且重复的,而对于进步青年的程序员来说是不能容忍重复的事情发生的.于是需要一种功能可以在集群中某实例部署后,集群中的其他tomcat实例会自动完成部署. 集群部署主要分两部分内容. 第一部分是关于应用传输问题,主要是关于在tomcat中如何一个web应用传输到其它tomcat实例上: 第二部分是应用部署方式及应用更新方式,主要关于在tomcat中

Tomcat集群的三种负载均衡方式优缺点对照。

1.使用DNS轮询.2.使用Apache R-proxy方式.3.使用Apache mod_jk方式. DNS轮询的缺点是,当集群中某台服务器停止之后,用户由于dns缓存的缘故,便无法访问服务,必须等到dns解析更新,或者这台服务器重新启动.还有就是必须把集群中的所有服务端口暴露给外界,没有用apache做前置代理的方式安全,并且占用大量公网IP地址,而且tomcat还要负责处理静态网页资源,影响效率.优点是集群配置最简单,dns设置也非常简单. R-proxy的缺点是,当其中一台tomcat停

Windows Server 2003 下配置 MySQL 集群(Cluster)教程

  这篇文章主要介绍了Windows Server 2003 下配置 MySQL 集群(Cluster)教程,本文先是讲解了原理知识,然后给出详细配置步骤和操作方法,需要的朋友可以参考下 MySQL 群集是 MySQL 适合于分布式计算环境的高可用.高冗余版本.它采用了 NDB Cluster 存储引擎,允许在 1 个群集中运行多个 MySQL 服务器.在 MySQL 5.0 及以上的二进制版本中,以及与最新的 Linux 版本兼容的 RPM 包中提供了该存储引擎. MySQL 群集是一种技术,

session-apache tomcat集群Session 共享后报错!

问题描述 apache tomcat集群Session 共享后报错! 我参考http://www.blogjava.net/killme2008/archive/2007/03/13/103607.html 实现session共享.然后我把我的工程放到tomcat 里面去.启动不报错.点击登录的时候就登录不进去.多次点击登录按钮会进入到主界面然后又强制退出到登录界面.我的tomcat集群版本是Apache 2.2.25Tomcat-7.0.55 点击登录的时候报:严重: Manager [loc

通向架构师的道路(第五天)之tomcat集群-群猫乱舞

一.为何要集群 单台App Server再强劲,也有其瓶劲,先来看一下下面这个真实的场景. 当时这个工程是这样的,tomcat这一段被称为web zone,里面用spring+ws,还装了一个jboss的规则引擎Guvnor5.x,全部是ws没有service layer也没有dao layer. 然后App Zone这边是weblogic,传输用的是spring rmi,然后App Zone这块全部是service layer, dao layer和数据库打交道. 用户这边用的是.net,以w

Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)

ORACLE集群概念和原理(二) Oracle集群概念和原理 Oracle的三种高可用集群方案 1 RAC(Real Application Clusters)                         多个Oracle服务器组成一个共享的Cache,而这些Oracle服务器共享一个基于网络的存储.这个系统可以容忍单机/或是多机失败.不过系统内部的多个节点需要高速网络互连,基本上也就是要全部东西放在在一个机房内,或者说一个数据中心内.如果机房出故障,比如网络不通,那就坏了.所以仅仅用RAC