zoukankan      html  css  js  c++  java
  • 如何实现 集群化/Session 复制-doc(cluster-howto.html)

    源文档链接: http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html 

    翻译日期: 2014年3月19日

    翻译人员: 铁锚

    感受: Tomcat 的这个集群有很多问题, 所以如果需要做分布式集群,最好使用无状态的应用程序,外加缓存系统。假如改造旧系统,那么也许可以参考一下。

    翻译如下:

    Apache Tomcat 6.0

    如何实现 集群化/Session 复制

    重要提示

    也可以查阅 cluster配置参考文档.

    内容列表
    快速设置

    只要在 <Engine> 节点 或者 <Host> 节点内部加上下面的代码即可支持集群化:

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

    上面的配置将开启 all-to-all session 复制,并通过 DeltaManager 来复制 session 增量. 采用 all-to-all 方式意味着 session 会被复制到此集群中其他的所有节点. 对于很小的集群,这种方式很适用, 但我们不推荐在较大的集群中使用(有很多 tomcat 节点的情况,译者注: 例如,几十个节点及以上...). 另外,使用 delta 增量管理器时,即使 某些节点没有部署应用程序,也会复制 session 到所有节点上. 
    要在较大的集群上进行session复制,您需要使用 BackupManager. 此 manager 只复制 session 数据到一个备份节点, 并且只复制到部署了对应应用程序的那些节点. BackupManager的缺点: 经过测试,性能不如 delta manager. 
    下面是一些重要的默认值: 
    1. 默认的 Multicast (组播)地址是: 228.0.0.4 
    2. 默认的 Multicast (组播)端口是: 45564 (端口号和地址组合以后就决定了 cluster 关系,被认为是同一个集群). 
    3. 默认广播的IP java.net.InetAddress.getLocalHost().getHostAddress() (确保你不是广播到 127.0.0.1, 这是一个常见的错误) 
    4. 默认的监听复制消息的 TCP 端口是在 4000-4100 范围内第一个可用的server socket。 
    5. 配置了两个监听器: ClusterSessionListener 和 JvmRouteSessionIDBinderListener 
    6. 配置了两个拦截器: TcpFailureDetector 和 MessageDispatch15Interceptor 
    下面是默认 cluster 配置信息的完整列表(效果和上面只配置一行是一样的): 

            <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>    
        

    本文稍后将详细介绍此节的信息.

    Cluster 基础

    要在 Tomcat 6.0 容器中执行 session 复制, 需要完成下列步骤:

    • 所有存放到 session attributes 中的对象必须实现 java.io.Serializable 接口
    • 将 server.xml 中的 Cluster 元素取消注释(或者加上此元素)
    • If you have defined custom cluster valves, make sure you have the ReplicationValve defined as well under the Cluster element in server.xml
    • 如果多个 Tomcat 实例是运行在同一台机器上, 确保 tcpListenPort 属性对每个实例都是唯一的, 在大多数情况下 Tomcat 会自己解决这个问题(如果没指定的话),通过 自动检测 4000-4100 范围内的可用端口号.
    • 确保在项目的 web.xml 文件中 web-app 根节点内加上 <distributable/> 元素
    • 如果使用 mod_jk, 请确保在 Engine 节点上设置了 jvmRoute 属性 < Engine name="Catalina" jvmRoute="node01"> ,并且 jvmRoute 属性值与 workers.properties 中的 worker name 对应
    • 确保所有的节点有相同的时间,并都采用 NTP 服务来同步!
    • 确保 loadbalancer 负载均衡器配置了 sticky session 模式.

    负载均衡可以通过多种方式实现, 可以参考 Load Balancing 文档.

    注意: 请记住在Java中 session 状态是通过一个 cookie 来跟踪的, 所以客户端看到的 URL 必须是一致的(host,port), 否则就会创建一个新的 session.

    注意: 当前要支持 Clustering 需要 JDK 版本号 1.5 或更高.

    Cluster 模块使用的是 Tomcat JULI 日志框架, 因此你可以通过常规的 logging.properties 文件来配置. 要打印日志跟踪信息, 可以通过 key: org.apache.catalina.tribes.MESSAGES 来启用日志功能.

    概述

    要在Tomcat中启用 session 复制, 下面的3种不同的途径都可以达成同样的目的:

    1. 使用 session 持久化, 并保存session到一个共享的文件系统中 (PersistenceManager + FileStore)
    2. 使用 session 持久化, 并保存session到一个共享的数据库中 (PersistenceManager + JDBCStore)
    3. 使用 内存复制(in-memory-replication), 通过 Tomcat 6 附带的 SimpleTcpCluster (lib/catalina-tribes.jar + lib/catalina-ha.jar)

    在这个版本的 session 复制中, Tomcat 可以通过 DeltaManager来进行 all-to-all 方式的session复制, 也可以通过 BackupManager 将session备份复制到单个节点. all-to-all 复制算法只在集群很小时具有高效率. 对较大的集群, 可以使用 主备会话复制(primary-secondary session replication), 只需要简单地配置 BackupManager 即可将会话信息复制到备份节点. 
    那么现在你可以使用domain worker 属性 (要求 mod_jk > 1.2.8) 通过DeltaManager来构建集群分区的可伸缩集群解决方案 (为此需要配置域名拦截器[domain interceptor]). 为了在一个 all-to-all 环境中降低复制所消耗的网络流量, 可以将集群切分为更小的组. 通过为不同 group 使用不同的组播地址(multicast addresses)这可以很容易地实现. 一个很简单的集群配置如下所示:

               DNS 轮询
                   |
             Load Balancer
              /           
          Cluster1      Cluster2
          /             /     
      Tomcat1 Tomcat2  Tomcat3 Tomcat4
    

    需要郑重指出的是, 会话复制(session replication) 只是集群化的起步. 另一个用于实现集群的流行概念是farming, 例如, 你只需要部署 app 到一台服务器上, 则集群会自动将此部署分发到整个集群中.这是所有可以和 FarmWarDeployer 一起使用的功能(参见server.xml 中的集群示例 )

    下一节将深入讲解会话复制(session replication )的工作原理,以及如何配置它.

    集群信息

    集群关系是通过广播心跳包来建立的. 因此,如果想要细分集群,可以通过改变组播IP地址或 <Membership>元素中的端口号来实现.

    心跳包括Tomcat节点的IP地址以及Tomcat监听复制通信的TCP端口号. 所有数据交换使用的都是在TCP协议.

    参数 ReplicationValve 用来决定何时请求完成,何时对复制进行初始化, 如果 session 改变了(通过调用 session 的 setAttribute 或 removeAttribute 方法),才会复制那部分数据.

    最重要的注意事项之一就是同步和异步复制的性能对比. 在同步复制模式下请求不会立刻返回,需要等待复制的session被发送到集群中的其他所有节点,并处理完成后才会返回. Synchronous(同步) vs. asynchronous(异步) 通过 channelSendOptions 标志进行配置,类型为整数型. SimpleTcpCluster/DeltaManager 的默认值都是 8, 也就是异步的(asynchronous). 更多信息请参考 send flag(overview) 或者 send flag(javadoc). 在异步复制期间, 在数据被复制之前,客户端请求就已经返还了. 异步复制拥有更短的响应时间, 而同步复制则保证 session 信息在请求返回之前被复制.

    崩溃后绑定会话到故障转移节点

    如果你使用了 mod_jk 却没有使用 sticky sessions 或由于某些原因 sticky session 没有生效, 或者只是简单的故障转移, 则 session id 需要被修改,因为其中包含了原来 tomcat 的 worker id (在Engine 元素中通过jvmRoute 定义). 要解决这个问题, 将要使用到 JvmRouteBinderValve.

    The JvmRouteBinderValve 重写 session id 以确保在故障转移后,下一个请求仍然是粘连的 (并不会因为 worker 的不可用就被回退到其他的随机节点). 该 valve(阀门) 将会重写 cookie中的 JSESSIONID 值,当然,使用的是同样的名字(name). 假如没有正确地设置 valve, 将使 mod_jk 模块在失败后很难保持会话的粘连。

    如果没有配置阀门(valves),会添加默认的 JvmRouteBinderValve, 同时会添加名为 JvmRouteSessionIDBinderListener 的集群消息侦听器(listener),以用来在故障转移发生时执行重写 session id 到集群中的其他节点。 记住,如果你在 server.xml 中添加自定义的阀门和监听器, 则默认设置就不再生效,请确保添加了所有和默认设置兼容替换的阀门和监听器。

    提示: 
    通过属性 sessionIdAttribute 可以更改包括旧 session id 的请求属性名。 默认属性名为org.apache.catalina.cluster.session.JvmRouteOrignalSessionID

    技巧: 
    您也可以在删除一个节点之前通过 JMX 启用 mod_jk 的转移模式 到所有备份节点! 备份节点上在所有的 JvmRouteBinderValve 备份节点上设置 enable为 true, 禁用mod_jk 的 worker, 然后删除节点并重启!然后再次启用mod_jk Worker 和禁用JvmRouteBinderValves。这个用法意味着只有请求会话被迁移。

    配置示例
            <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                     channelSendOptions="6">
    
              <Manager className="org.apache.catalina.ha.session.BackupManager"
                       expireSessionsOnShutdown="false"
                       notifyListenersOnReplication="true"
                       mapSendOptions="6"/>
              <!--
              <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="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>
        

    我们一项项地来解读!!

            <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                     channelSendOptions="6">
        

    Cluster是主要的元素,所有集群相关的详细配置都包含在元素内部. SimpleTcpCluster类或调用 SimpleTcpCluster.send 方法发送的每个消息, 都会附加上 channelSendOptions 这么一个标志. 关于发送标志的详细描述信息可以参考 Tomcat 官方 javadoc . DeltaManager 调用 SimpleTcpCluster.send 方法来发送消息, 而 backup manager 则自己直接通过channel来发送. 
    想要了解更多信息, 请访问 集群配置参考文档

              <Manager className="org.apache.catalina.ha.session.BackupManager"
                       expireSessionsOnShutdown="false"
                       notifyListenersOnReplication="true"
                       mapSendOptions="6"/>
              <!--
              <Manager className="org.apache.catalina.ha.session.DeltaManager"
                       expireSessionsOnShutdown="false"
                       notifyListenersOnReplication="true"/>
              -->        
        

    这是一个用于 manager 配置的模板,当 <Context> 元素中没有定义 manager 时作为默认值. 在 Tomcat 5.x 中每个标记为 distributable 的 webapp 都需要使用同一个manager。 但从 Tomcat 6 开始就没有这样的限制了, 可以为每个 webapp 指定一个 manager 类, 因此在 cluster 中可以存在多种 managers. 显然, 在一个节点中某个应用程序的 管理器 必须同集群中其他节点同一个应用的管理器保持一致。 如果 webapp 被标记为 <distributable/> , 而webapp又没有自定义 manager, Tomcat 就会使用此模板克隆一个 manager 实例. 
    想要了解更多信息, 请访问 集群manager配置参考文档

              <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        

    channel 元素是 Apache Tribes(Tribes,一群的), Tomcat 内部使用的 group 通讯框架. 该元素封装了通讯和成员关系需要用到的一切.
    想要了解更多信息, 请访问 集群channel配置参考文档

                <Membership className="org.apache.catalina.tribes.membership.McastService"
                            address="228.0.0.4"
                            port="45564"
                            frequency="500"
                            dropTime="3000"/>
        

    Membership 是通过 组播(multicasting) 建立的. 请注意 Tribes 也支持使用 StaticMembershipInterceptor 来设置静态的成员关系, 如果你想要不使用组播来扩展成员关系的话。 address 属性是要使用的广播地址, port 属性是广播的端口号. 两者组合在一起创建了集群区分(cluster separation). 如果你想要一个可靠(QA cluster) 的生产集群(production cluster), the easiest config is to have the QA cluster be on a separate multicast address/port combination the the production cluster. 最简单的配置是使 QA集群在 一个分开的多播地址/端口组合成生产集群 
    membership 组件 广播其自身的 TCP adress/port 到其他节点 以 在 TCP 上完成 节点间的通信. 请注意被广播的地址是Receiver.address 属性 中的一个. 
    想要了解更多信息, 请访问 reference documentation

                <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                          address="auto"
                          port="5000"
                          selectorTimeout="100"
                          maxThreads="6"/>
        

    在 tribes 中,发送与接收数据的逻辑已经被分解到两个功能组件中. Receiver, 顾名思义, 负责接收消息. 因为 Tribes stack 是线程无关的(thread less), (这是一个很受欢迎的改进,其他框架也在使用), 所以在此组件中有一个线程池,并且可以设置 maxThreads 和 minThreads 参数. 
    address 属性是将要通过membership 组件广播给其他节点的 host 地址. 
    想要了解更多信息, 请访问 集群 receiver 配置参考文档

                <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
                  <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
                </Sender>
        

    sender 组件, 见名知意,负责发送消息给其他节点. sender 有一个 shell 组件, 即 ReplicationTransmitter, 但是真正干活的是其子组件Transport. Tribes 支持 sender 池, 所以消息可以并行(Parallel)发送, 如果使用 NIO sender,还可以并发地(Concurrently)发送消息.
    并发(Concurrently) 的意思是同一时间条消息对于多个 sender; 而并行(Parallel) 的意思是同一时间条消息对应多个 sender. 
    想要了解更多信息, 请访问 集群 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>
        

    Tribes 发送消息要经过一个栈(stack). 栈中的元素被叫做拦截器(interceptor), 工作机制类似于 Tomcat servlet container中的valve阀门. 使用拦截器, 运算逻辑可以分解成可管理的多个代码片断. 上面配置的 interceptors 是: 
    TcpFailureDetector - 通过TCP验证崩溃的节点, 如果组播数据包丢失, 这个拦截器防止假活跃(false positives), 即便节点仍然是存活的,但被标记为崩溃状态的情况. 
    MessageDispatch15Interceptor - 分派消息到线程(池)来异步地(asynchrously)发送消息。 
    ThroughputInterceptor - 打印出简单的信息统计流量. 
    请注意 interceptors 的顺序是很重要的. 他们定义在 server.xml 中的顺序决定了他们在 channel stack 中的表现方式. 可以把他看成一个 linked list, head 是第一个拦截器,而 tail 是最后一个. 
    想要了解更多信息, 请访问 集群 interceptor 配置参考文档

              <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                     filter=".*.gif;.*.js;.*.jpg;.*.png;.*.htm;.*.html;.*.css;.*.txt;"/>
        

    集群使用阀门(valve)来根据requests 找到 web applications, 我们在上面提到过 ReplicationValve 和 JvmRouteBinderValve. <Cluster> 元素本身并不是Tomcat管道的一部分, 而是cluster 将 valve 添加到其父容器中. 假如 <Cluster> 元素被配置到 <Engine> 元素中, 那么 valves 就会被加到 engine 里,诸如此类. 
    想要了解更多信息, 请访问 集群 valve 配置参考文档

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

    默认的tomcat集群支持 farmed 部署,即集群可以部署和卸载在其他节点上的应用程序。该组件目前的状态在不断变化,但很快就会得到解决。 在 Tomcat 5.0 和5.5 之间的部署算法发生了变化, 在这一点上,该组件的逻辑改变为 部署目录必须匹配 webapps目录。 
    想要了解更多信息, 请访问 集群 deployer 配置参考文档

              <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
            </Cluster>
        

    因为 SimpleTcpCluster 自身是 Channel object 的一个 sender 和 receiver, 所以其他组件可以注册成为 SimpleTcpCluster 的监听器(listener). 上面的 ClusterSessionListener 监听着 DeltaManager 的 复制消息(replication messages) 并应用 manager 的增量已经 反过来应用到 session中.. 
    想要了解更多信息, 请访问 集群 listener 配置参考文档

    集群架构

    Component Levels(组件级别):

             Server
               |
             Service
               |
             Engine
               |   
               |  --- Cluster --*
               |
             Host
               |
             ------
            /      
         Cluster    Context(1-N)                 
            |             
            |             -- Manager
            |                   
            |                   -- DeltaManager
            |                   -- BackupManager
            |
         ---------------------------
            |                       
          Channel                    
        ----------------------------- 
            |                          
         Interceptor_1 ..               
            |                            
         Interceptor_N                    
        -----------------------------      
         |          |         |             
       Receiver    Sender   Membership       
                                             -- Valve
                                             |      
                                             |       -- ReplicationValve
                                             |       -- JvmRouteBinderValve 
                                             |
                                             -- LifecycleListener 
                                             |
                                             -- ClusterListener 
                                             |      
                                             |       -- ClusterSessionListener
                                             |       -- JvmRouteSessionIDBinderListener
                                             |
                                             -- Deployer 
                                                    
                                                     -- FarmWarDeployer
          
          
    

    运行机制

    为了您能够快速容易地理解集群的运行机制, 我们将引导您体验一些列具体情境. 在情境中我们只使用两个Tomcat实例: TomcatA 和TomcatB . 并涵盖下面的事件序列:

    1. 启动 TomcatA
    2. (在 TomcatA 完全启动之后)启动 TomcatB
    3. TomcatA 收到一个请求,则创建一个 session,假设为 S1.
    4. TomcatA 崩溃了
    5. TomcatB 收到一个来自 session S1的请求
    6. TomcatA 启动
    7. TomcatA 收到一个请求, 调用 session (S1) 的 invalidate 方法使其失效
    8. TomcatB 收到一个请求, 属于一个新的 session: (S2)
    9. 因为不活动, TomcatA 中 session S2 超时.

    OK,现在我们有一个很好的顺序,我们将带你通过 session repliction 代码中 了解到底发生了什么

    1. 启动 TomcatA

      Tomcat 使用标准的启动顺序进行启动(starts up). 当 Host object 创建时, 会关联上一个 cluster object. 在解析 contexts 时, 如果在 web.xml 中存在 distributable 元素,则 Tomcat 通知 Cluster 类 (此时是 SimpleTcpCluster) 创建复制上下文(replicated context)的管理器(manager). 启用了集群, 在 web.xml 中设置了 distributable, Tomcat 会为 context 创建一个DeltaManager ,而不是使用 StandardManager. cluster 类将启动一个 membership service (广播) 以及一个 replication service (tcp单播). 在本文档下面将会介绍更多的架构信息。

    2. 启动 TomcatB

      当TomcatB启动时,它遵循TomcatA一样相同的序列,只有一个例外。集群启动,并将建立一个成员关系(TomcatA TomcatB)。 TomcatB现在将请求服务器集群中已经存在的会话状态,在这种情况下也就是TomcatA。 TomcatA响应请求,在TomcatB开始监听HTTP请求之前,状态已经从TomcatA传输到了TomcatB。如果TomcatA不回应,TomcatB将在 60秒后超时,并报告一个日志条目。每个在 web.xml 中标记了 distributable 的web应用程序的会话状态都会得到传输。 注意: 要有效地使用会话复制,所有tomcat实例都应该配置成一样。

    3. TomcatA 收到一个请求, 创建 session S1 .

      来到TomcatA的请求处理就和没有会话复制时完全一样。当请求完成后,ReplicationValve在响应返回给用户将拦截请求,并激发一些行为。此时会发现session 已被修改,它会使用TCP复制会话信息给 TomcatB。 一旦序列化数据交给操作系统TCP逻辑,请求就通过阀门的管道返回给用户。对每个请求整个会话都被复制,这使得修改属性的代码在会话中不用调用setAttribute或removeAttribute也会被复制。 一个useDirtyFlag配置参数可以用来优化会话复制的次数。

    4. TomcatA 崩溃

      当TomcatA崩溃,TomcatB接收通知,TomcatA退出集群。TomcatB从其成员列表删除TomcatA,TomcatA将不再收到发生在TomcatB任何变化的通知。负载平衡器将所有会话(包括当前会话)请求从TomcatA重定向到TomcatB。

    5. TomcatB 收到一个来自 session S1的请求

      没有什么可激动的,TomcatB会处理此请求,就和其他普通请求一样.

    6. TomcatA 启动

      TomcatA开始接受新的请求之前,将会根据上面描述的启动序列 1) 2) 来进行启动。它将加入到集群中,联系TomcatB获取所有会话的当前状态。一旦它收到会话状态,它完成装载并打开HTTP / mod_jk 端口。所以没有请求发给TomcatA,直到它从TomcatB接收完会话状态。

    7. TomcatA 收到一个请求, 调用 session (S1) 的 invalidate 方法使其失效

      invalidate 调用会被拦截, 并且 session 会被加入失效会话队列。 在请求完成时,不会发送会话改变消息, 而是发送一个“expire”消息给TomcatB, TomcatB也会让此会话失效。

    8. TomcatB 收到一个新的请求, session (S2)

      (同步骤 3)

    9. 因为不活动, TomcatA 中的 session S2 超时.

      当一个会话被用户标记失效时 invalidate 调用会被拦截, session 会被加入失效会话队列。此时,失效的会话不会被复制,直到另一个请求通过系统并检查无效队列。

    Phuuuhh! :)

    Membership 集群成员关系关系是通过使用非常简单的多播ping建立的。每个Tomcat实例都会周期性地发送一个 multicast ping,在 ping 消息中包含 tomcat 实例自身的IP和配置的TCP监听端口。如果实例在一个给定的时间内没有收到这样的ping信息,就会认为那个成员down掉了。非常简单,非常有效!当然,您需要在您的系统上启用广播。

    TCP Replication 一旦收到一个多播ping 包,在下一个复制请求时成员被添加到集群, 发送实例将使用的host 和 port 信息和建立TCP套接字。使用该套接字发送序列化的数据。我选择TCP套接字的原因是因为它建立了流量控制和保证交付。所以我知道,当我发送一些数据时,它就会到达那里 :)

    Distributed locking and pages using frames Tomcat在跨集群同步不保持会话实例。这种逻辑的实现将是多开销和导致各种各样的问题。如果你的客户用同一个会话同时发送多个请求,那么最后的请求将会覆盖集群中的其他会话。

    在线 FAQ

    请访问 在线 FAQ 的集群化相关部分.

  • 相关阅读:
    什么是守护线程?
    如何优雅地停止一个线程?
    如何创建、启动 Java 线程?
    什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
    并行是什么意思?与并发的区别是什么?
    并发编程的缺点?
    BZOJ_3058_四叶草魔杖_kruscal+状压DP
    BZOJ_3476_[Usaco2014 Mar]The Lazy Cow_扫描线+切比雪夫距离
    BZOJ_1511_[POI2006]OKR-Periods of Words_KMP
    BZOJ_3479_[Usaco2014 Mar]Watering the Fields_Prim
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467028.html
Copyright © 2011-2022 走看看