该文档翻译自tomcat 帮助文档,下面主要说的是session的复制机制。(英文水平太烂,第一次发译文,请读者见谅)
1:在server.xml中的<Engine> 或者<Host>中添加下面内容
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> |
通过上面的配置,可以实现使用DeltaManager来实现session的all-to-all的复制。所谓的all-to-all复制是一个节点的session将会被复制到所有的其他的节点[Bruce1] 。这在小集群当中是相当有效的,但是当存在大集群的时候,也就是集群中有很多的tomcat节点的时候,我们不推荐这么做。当使用delta manager进行session复制的时候,即使节点中没有应用部署,session也会被复制。
避免这种情况的办法,你可以使用BackManager。该管理器只会将session复制到备份节点中。并且只会复制到部署应用的节点中。
下面是几个重要的默认值:
1:组播地址为 222.0.0.4
2:组播端口是 45564(端口和地址一起决定了集群成员节点)
3:IP广播是java.net.InetAddress.getLocalHost().getHostAddress
4:
<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>
集群基本
要在tomcat7中实现集群,需要实现以下步骤:
u Session中的所有的属性都需要是可序列化的
u 在你的server.xml中,注释掉Cluster节点
u 如果你已经定义了集群值,确保在server.xml下的cluster节点下的存在 ReplicationValve 值
u 如果你的tomcat多个实例运行在同一个机器上,确保 tcpListenPort 属性是不同的。通常,tomcat会智能检测在4000-4100之间的可用端口。
u 如果你使用 mod_jk ,确保jvmRoute属性设置了 <Enginename="Catalina" jvmRoute="node01" > 并且,jvmRoute 同你在 workers.properties中的 worker name是一致的。
u 确保所有的机器的时间都是一致的。并且用NTP进行时间同步[Bruce2]
u 确保你的 loadbalancer (负载均衡)配置了 sticky session模式[Bruce3]
负载均衡可以通过很多的技术实现。
注意:你的session是通过cookie 来进行关联的。所以,你的URL从外部看一定是一致的,否则,将会生成一个新的session。
集群的配置需要jdk1.5或更高版本的支持。
集群模块采用的是Tomcat的JULI日志框架。所以,你可以通过 logging.properties文件来配置日志。
概述
要在tomcat中实现 session的复制,可以通过三种不同的方式达到相同的效果。:
u 使用session的持久化,并且将session存储在 共享文件系统中。
u 使用session持久化,并将session存储到数据库中。
u 使用内存复制机制。使用简单的 tcp集群
在发布的session复制方案中,tomcat使用DeltaManager 来实现 all-to-all的session复制或者使用BackupManager 将session复制到一个节点中。All-to-all复制算法只适用于小集群。对于大集群,采用主备session复制,这样,session只会复制到备用服务器中。
当前,你使用 domain workerattribute(mod_jk1.2.8以上)来构建集群划分。这种构建方式可以解决潜在的系统构建的伸缩问题。为了确保网络通讯,你可以讲集群分成若干个组。他们可以通过不同的组播地址轻易的区分。这种结构简单来说就是如下这种情况:
DNS Round Robin
|
Load Balancer
/ \
Cluster1 Cluster2
/ \ / \
Tomcat1 Tomcat2 Tomcat3 Tomcat4
需要注意的是:session的复制只是集群开始。另一个实现集群的流行的概念是 farming。比如说,你在一个服务器上部署了应用,然后集群会把该应用分别部署在集群中的各个节点。这个能力可以通过 FarmWarDeployer 深入探究(server.xml中cluster的一种实现)。
集群信息
节点成员是通过组播的心跳来建立的。所以,如果你想拆分你的集群,你通过改变组播地址和端口来实现。
心跳包括了ip地址和tomcat监听的session复制的TCP端口。所有信息的交互都是通过tcp协议实现的。
ReplicationValve 这个值用来找出 request是什么时候完成并开始session复制的。该值只有在session发生变化,也就是调用setAttribute或者调用removeAttribute方法时,才进行复制。
一个性能最重要的考虑就是同步复制还是异步复制的问题。在同步复制中,request在session信息复制到其他的节点之后,才可用。是同步复制还是异步复制是通过 channelSendOptions( int 类型)来配置的。对于 SimpleTcpCluster/DeltaManager来说,默认值是8,他是异步的。具体配置你可以通过下面两个连接,获得更多信息。
sendflag(overview) or the sendflag(javadoc)
在异步复制过程中,request在session同步完成之前就可用。异步可以缩短处理请求的时间。同步处理保证request返回前,session已经同步完成。
节点崩溃后,绑定session
如果你使用mod_jk 但是没有使用sticky session或者因为某些原因,sitcky没有起作用,或者你的tomcat崩溃了,session的id需要被修改因为他之前包含了worker 的ID,也就是之前tomcat的ID。为了解决这个问题,我们使用 JvmRouteBinderValve。
在一个tomcat节点崩溃后,JvmRoutrBinderValue重写session ID来确保下一个请求将会粘滞(也就是说不会回到随意的节点因为之前的节点已经不可用了)。该阀会用同样的值重写在cookie中的jessionID。如果没有配置该阀,使用mod_jk实现sticky可能就比较难了。
默认的,如果没有阀被配置,那么JvmRouteBinderValve就会被加入。集群消息监听器(jvmRouteSessionIDBinderLinstener)也是被默认设置的,并且被用于一旦有节点崩溃,向其他节点重写sessionID。注意,如果你在server.xml中实现自己的阀或者实现自己的监听器,那么默认的则会失效。所以确保你加入正确的阀和监听器。
配置demo:
<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|.*\.jpeg|.*\.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是主要的元素,在这个元素中,集群的配置的所有细节都在这里面。channelSendOpentions 是通过SimpleTcpCluster发送的消息的标示,或者任何调用SimpleTcpCluster.send方法的对象。这个标记的说明在http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/tribes/Channel.html
DelatManager是通过SimpleTcpCluster.send方法发送消息,而backup manager则是通过通道,他自己直接发送到的。
<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配置的话,默认就用这个了。在tomcat5.x中,每一个app应用必须用同一个manager,但在该版本的tomcat中,你可以为每一个webapp定义manager。所以,你可以在你的集群中混合配置manager。很显然,每一个节点中的manager需要同集群中的其他的节点的manager是一致的。如果没有为webapp配置manager,并且webapp被标记成<distributable/>,tomcat将会采用这个manager的配置并且生成一个manager的实例。关于manager的配置,参考下面链接:
http://localhost:8080/docs/config/cluster-manager.html
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
这个channel元素是一个部落??,一个在tomcat中的组交流框架。该元素将所有和交流相关以及成员之间组织关系封装起来。详情参考:
http://localhost:8080/docs/config/cluster-channel.html
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
membership是通过组播完成的。注意如果你想扩展你的membership而超越组播,可以通过使用StaticMembershipInterceptor来支持静态的membership。Address属性是组播地址,端口为组播端口。地址和端口共同组成了集群的分割。如果你要一个QA(质量保证)集群和一个生产集群,最简单的配置方式是将QA集群做成一个独立的组播地址和端口然后和生产集群组合。
Membership组件广播TCP地址和端口到其他的节点然后节点之间就可以进行交流了。请注意,被广播的地址是Receiver.address 的属性。
更多消息参考:
http://localhost:8080/docs/config/cluster-membership.html
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="5000"
selectorTimeout="100"
maxThreads="6"/>
这部分配置的是发送和接收数据的被分成了两个独立的部分。上面负责的是接收数据。因为部落栈对线程比较有需求,所以,这需要配置一个线程池,该线程池中有最大和最小数量的设置。地址属性是需要向其他地址广播的地址。更多信息参考:
http://localhost:8080/docs/config/cluster-receiver.html
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
Sender组件,负责向其他节点发送的信息的。Sender是一个shell组件:ReplicationTransmitter,但是真正完成这一工作的是他的子组件:Transport。他支持一个sender池,所以,消息可以并行的发送,如果你使用了NIO,那么消息可以并发的发送。并发意味着一个消息在同一时刻到多个sender,平行意味着多个消息在同一时刻到多个sender。跟多消息参考:
http://localhost:8080/docs/config/cluster-sender.html
集群的结构:
| |
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. tomcatB启动(等TomcatA启动完毕后)
3. tomcatA收到一个请求,session S1生成。
4. tomcatA宕机
5. tomcatB收到一个来自S1的请求。
6. tomcatA启动。
7. tomcatA收到一个请求,session被调用Invalidate(S1)
8. tomcatB收到一个请求,生成session S2
9. tomcatA session S2因为静止,所以被过期。
好了,我们已经有一个剧情发展的序列了,我们将会见识一下啊session复制的过程。
1. tomcatA启动
tomcat 按照标准的正常配置启动。当Host对象被构建,一个cluster对象和他关联。当contexts被解析,如果在web.xml中存在distrubutable元素,tomcat要求集群类(在该配置情况下,是SimpleTcpCluster)为复制的context创建一个manager。所以,如果采用集群,在web.xml中设置distributable,tomcat将会为context生成一个DeltaManager,而不是标准的StandardManager。集群类将会启动一个membership服务(组播)和一个复制服务(TCP 单传)。
2. tomcatB启动
当tomcatB启动,他按照tomcatA同样的顺序启动。但是有一个不一样的是集群被启动并且建立了membership(tomcatA和tomcatB),tomcatB将会请求已经在集群中存在的服务器(也就是tomcatA)的session情况。tomcatA对请求响应,并且在tomcatB江亭HTTP请求之前,将tomcatA中的session传送到tomcatB中。为防止tomcatA不响应,tomcatB将会在60秒之后超时,并生成一个日志记录。Session state将会为每一个在web.xml中配置distrubutable的web工程传输。注意,为了是session复制更有效率,你所有的tomcat实例配置应该是一样的。
3. tomcatA收到一个请求,生成session S1
当tomcat收到一个请求,tomcatA就像没有集群一样处理请求。当request完毕,才发生动作。 ReplicationValve将会在response返回用户之前拦截请求。在这个时候,他发现session被修改了,于是使用TCP复制session传向tomcatB。一旦已经序列化的数据被操作系统的TCP处理,request将会通过阀管道返回用户。对于每一个请求,整个session都会被复制(属性没变化也复制??)这就允许代码修改session中的属性而不调用setAttribute和removeAttribute。所以,使用 userDirtyFlag配置参数可以减少session被复制的次数。
4. tomcatA宕机
当tomcatA宕机,tomcatB收到收到一个tomcatA从集群中失落的通知。TomcatB将tomcatA从membership列表中移除。并且当tomcatB中的session发生变化,不再通知tomcatA。负载均衡将指向tomcatA的请求定向到tomcatB。
5. tomcatB收到来自session S1的请求
没什么特殊的处理,tomcatB就想处理其他请求一样处理该请求
6. tomcatA 启动
在tomcatA能够处理新的到自己的请求之前,他将会按照1,2步进行启动。他将会加入到集群中。联系TomcatB并同步所有的session。一旦他结束接受session state,他就停止加载并打开 http/mod_jk端口。所以不会有请求被发送到tomcatA直到他接收到了所有tomcatB的session。
7. tomcatA收到请求,session调用invalidate(S1)
调用invalidate被拦截,session和invalidated session进行排队。当请求被处理完毕,不是向外发送session已经被改变了,而是向tomcatB发送“session过期”消息。tomcatB将会是session失效。
8. tomcatB收到一个请求,生成一个新的session(S2)
过程和3 是一样的
9. TomcatA中,session S2因为静止而过期
Invalidate方法被调用时,被拦截,就像是用户要使session失效的过程一样。这时候,失效的session不会被复制到其他的节点。(有点不是特明白)
Membership:集群中的membership的建立是通过简单的组播ping。每一个tomcat定期的发送一个组播 ping,在ping的消息中,包含了该节点用于session复制的IP和TCP监听的端口。如果一个节点在给定的时间内没有收到任何的ping,那么认为这个节点是挂了的。当然,你需要在你的系统中建立组播的功能。
TCP 复制:一旦一个组播消息被接受,该成员就被加入到集群中,并进行复制请求,发送的实例通过host和端口机那里TCP socket,通过该socket,发送经过序列化的数据。为什么选择TCP socket是因为有包顺序控制和可信任链接(UDP相反)。
这里简单说一下组播的概念:
IP组播是指一个IP报文向一个“主机组”的传送,这个包含零个或多个主机的主机组由一个单独的IP地址标识。主机组地址也称为“组播地址”,或者D类地址。除了目的地址部分,组播报文与普通报文没有区别,网络尽力传送组播报文但是并不保证一定送达。
主机组的成员可以动态变化,主机有权选择加入或者退出某个主机组。主机可以加入多个主机组,也可以向自己没有加入的主机组发送数据。主机组有两种:永久组和临时组。永久组的IP地址是周知的,由Internet管理机构分配,是保留地址。临时组的地址则使用除永久组地址外的非保留D类地址。
IP组播分组在互联网上的转发由支持组播的路由器来处理。主机发出的IP组播分组在本子网内被所有主机组成员接收,同时与该子网直接相连的组播路由器会把组播报文转发到所有包含该主机组成员的网络上。组播报文传递的范围由报文的生存期值(TTL, Time-to-Live)决定,如果TTL值等于或者小于设置的路由器端口TTL门限值(TTL Threshold),路由器将不再转发该报文。
通过JMX监控集群
监控集群时很重要的。一些集群的对象是JMX beans
集群中的各个元素的用意及配置
集群元素
简介
集群中实现了session复制以及context属性的复制和war包的集群部署。因为集群配置是相当复杂的,默认配置对大多数人来说将会十分有用的。
Tomcat 集群的实现是可扩展的。因此,我们提供了很多的配置项,虽然配置项看起来很多,但是不要失去信心,你通过这些配置便有了很强大的配置。
是在engine配置还是在host配置的问题
你可以再server.xml中的 engine或者host元素中加入 Cluster元素。将其放入engine中意味着你在tomcat中所有的host都将支持集群。并且将共享消息组件。当你将cluster放入 Engine节点,那么集群会将每一个sessionManager的host name放入 manager name,这样,两个context即使用同样的名字,但是只要在两个不同的host中,也会被区分出来。
Context属性复制
要配置context属性复制,只需加入下面代码即可将app的context的context实现进行交换。
<Context className="org.apache.catalina.ha.context.ReplicatedContext"/>
配置内容
|
嵌入组件
Manager
集群中的manager是一个tomcat的session manager接口的一个实现。集群接口必须实现org.apache.catalina.ha.ClusterManager 并单独的负责session的复制。
现在有两种manager:org.apache.catalina.ha.session.DeltaManager复制集群中所有的session。这个实现被证明工作的很不错,但是有一个限制就是集群中的所有成员都是均匀的,所有的节点的配置都是一样的。还有一个manager就是org.apache.catalina.ha.session.BackupManager,他也可以进行session复制,但是只向备份节点进行复制。备份节点的位置是所有其他节点都知道的。他也支持不均匀部署。所以,manager知道所有web应用程序的位置。
在Cluster中定义的Manager元素是所有在web.xml中标记<distributable/>的工程的模板。然后,你也可以在context.xml中或者server.xml中定义Manager来重写每一个web应用的默认的实现。
|
|
|
Channel
Channel是我们被称为 apache tribes的主要组件。他管理一系列的子组件来构成一组交互框架。这个框架被那些需要同其他tomcat进行交互的组件内部使用。一个简单的这些组件的使用就是使用SimpleTcpCluster 中尉DeltaManager传递消息了或者BackupManager 使用不同的复制策略。ReplicatedContext (复制context)对象同样使用该通道进行context属性的交换。
Channel/Membership:
该组件主要是用于动态的发现集群中的其他节点的。
该集群成员通知是建立在想IP地址发送组播UDP请求的基础上的。集群成员通过使用同样的组播地址和端口联系在一起的。每一个成员按给定的时间间隔发送一次心跳,该心跳用于动态的发现。如果在 dropTime 时间内,没有收到心跳,那么该成员被认为是可疑的,并且该通道和所有的membership 监听器将会被通知。
组播属性
Attribute |
Description |
className |
默认值是:org.apache.catalina.tribes.membership.McastService 他是目前唯一的实现。该实现用组播心跳实现了成员发现。 |
address |
组播地址,用于组播他的存在,并且监听其他节点的心跳。默认的地址是228.0.0.4.确保你的网络实现了组播功能。 |
port |
组播端口,默认的是45564,端口同组播地址共同组成了集群组。要将你的集群分成若干个不同的组,或者要区分QA和生产环境,就更改地址或者端口。该参数之前是 acastAddr。 |
frequency |
心跳发出的时间间隔。默认是500ms。通常情况下,默认值是可以的。 |
dropTime |
如果一个节点在dropTime时间内没有发送心跳,则认为该成员超时,并通知Channel。默认值为3000ms。 |
bind |
如果你希望将组播到一个特定的网络接口中,使用该属性来配置。默认的或者该属性被省略,他将会绑定0.0.0.0 在多host情况下,可能会引起问题。 |
ttl |
time-to-live 缩写,用于组播心跳。该配置的值应该是介于0-255的值。默认值为VM 实现的配置。 |
domain |
Apache Tribes 通过domain属性,将逻辑组成员弄到一个domain下。调用下面方法返回这里设置的值。 org.apache.catalina.tribes.Member.getDomain() |
soTimeout |
在单线程中发送和收到心跳时间限制,所以呢,为防止线程阻塞,你可以控制在该线程上的SO_TIMEOUT值。如果该值很小或等于零,那就会频繁的达不到该值。 |
recoveryEnabled |
In case of a network failure, Java multicast socket don't transparently fail over, instead the socket will continuously throw IOException upon each receive request. When recoveryEnabled is set to true, this will close the multicast socket and open a new socket with the same properties as defined above. |
recoveryCounter |
When recoveryEnabled==true this value indicates how many times an error has to occur before recovery is attempted. The default is 10. |
recoverySleepTime |
When recoveryEnabled==true this value indicates how long time (in milliseconds) the system will sleep in between recovery attempts, until we either recovered successfully or we have reached the recoveryCounter limit. The default is 5000 (5 seconds). |
localLoopbackDisabled |
Membership uses multicast, it will call java.net.MulticastSocket.setLoopbackMode(localLoopbackDisabled). When localLoopbackDisabled==true multicast messages will not reach other nodes on the same local machine. The default is false. |
Channel/Sender:
他主要负责发送出去集群消息。默认的实现是org.apache.catalina.tribes.transport.ReplicationTransmitter。该发送器是个空壳,并没有多少逻辑。倒是<Transport>组件实现了实际的传输机制。
并发的平行传递
默认的 transport 实现是org.apache.catalina.tribes.transport.nio.PooledParallelSender
。apache Tribes 实现了我们称之为“平行并发传输”。这意味着我们可以我们可以在同一时刻将一个消息发送到多个终端(平行),将两个消息同时发送到一个终端(并发)。结合这两点,我们称之为“并发平行传输”
这个特性什么时候起作用呢?最简单的样例就是如果你的代码要发送10M的数据,比如一个war包部署的时候,你可以压入一个小的10k的消息来说明session被复制了而你不用等待10M的消息完成传输,因为另一个单独的线程将10k的消息也同时压入,并发不会被打断,暂停或者优先级控制,但以后版本会有。
包含元素:
包含元素Transport不是必须的,但是鼓励使用,因为这里可以配置所有的你发消息的socket配置。阅读下面配置,这有两个实现,一个是基于非阻塞的一个是基于阻塞IO的。
Org.apache.catalina.tribes.transport.bio.PooledMulitiSender是阻塞型的实现,org.apache.catalina.tribes.transport.nio.PooledParallelSender是阻塞型的实现。平行传输对于阻塞类型的传输是不可用的,因为他在发送数据的时候会阻塞线程。
Channel/Sender/Transport:
Channel/Receiver:
Channel/Interceptor:
Valve
集群阀同tomcat的其他的阀没有任何的区别。集群阀将会拦截http请求的处理链,集群的实现使用这些阀来智能的决定什么时候data需要被复制。
集群阀必须实现 org.apache.catalina.ha.ClusterValve接口。这是一个继承自org.apache.catalina.Valve的简单接口。