一、 配置:

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

与DeltaManager配置的区别就是将manager元素的className由DeltaManager换成了BackupManager;

二、 BackupManager会话管理原理:

1、 DeltaManager会话管理器采用的全节点复制,即每个session的创建、修改和释放都广播到集群中其他所有节点上,当集群节点增加时,网络流量会呈平方趋势增长,因此无法构建较大规模的集群,BackupManager会话管理器采取另一种会话管理方式,每个会话只有一个备份,他会使网络流量随节点数的增加呈线性趋势增长,大大减少了网络流量,可以构建较大规模的集群;
2、 backupManager会话管理器中存在三种类型的节点:源节点、备份节点和代理节点,创建会话时,该会话保存在该节点上,每次对这个会话的访问都被分配到这个节点上,这个节点被称为源节点,会话创建后,会在集群节点中找到一个节点用于存放该会话的备份,这个节点称为备份节点,集群中除了源节点和备份节点外,其他节点都会保存一个该会话的位置信息,这些节点被称之为代理节点;因此每个会话都有一个源节点,一个备份节点和若干个代理节点;
3、 如果某个会话的源节点宕机了,这时他的请求会随机分配到其他任意节点上,有两种情况:
  a) 分配到备份节点上:此时仍然能获取到该会话,同时将这个节点上的这个会话标记为源节点,且继续选取一个其他节点作为该会话的备份节点,并将会话信息拷贝到新的备份节点上;
  b) 分配到了代理节点上:此时肯定在代理节点上找不到该会话,于是他向集群所有节点查询该会话,该会话的备份节点收到查询请求后,将该会话信息拷贝到代理节点上,此代理节点升级为该会话的源节点,同时告知集群中其他节点,该会话的源节点已经变更;
4、 集群节点列表的维护主要是通过启动时向所有节点广播节点信息以及心跳去维护,如下图所示:n1启动时向其他节点广播自己的信息,其他节点收到信息后将n1添加到自己的列表,而n1则把n2,n3,n4添加到自己的列表,接着按照一定的时间间隔向其他节点发心跳,如下图,假如n2未给n1响应信息,n1则把n2从自己的列表中删除;

5、 backupManager使用Round robin算法用于备份节点的选择,按照顺序依次从集群节点列表中选择节点,代码如下:

三、 UML图:

1、 会话管理器其实就是对会话集操作的封装,从设计角度看,为了改变会话集的操作行为,只需继承ConcurrentHashMap类并重写其中一些方法即可实现,例如put、get、remove等等操作实现跨节点操作。于是tomcat的BackupManager对整个会话集的跨节点操作被封装到一个继承ConcurrentHashMap类的LazyReplicatedMap子类中;
2、 AbstractReplicatedMap类的innerMap成员变量保存了sessionId和MapEntry的映射关系,MapEntry则是对session、源节点成员及备份节点等的封装,从上面的UML图可以看出MapoEntry的成员变量:primary存储了该session的源节点信息,backupNodes存储了备份节点信息,backupNodes虽然是一个数组,但是里面永远只有一个元素,key和value存储了sessionId和session对象,backup是个布尔类型,表示该session节点是否是备份节点,proxy表示是否是代理节点,copy表示是否是copy节点;
3、 要在集群节点之间通信和发消息,需要定义通信协议以及信息载体,而这个协议以及信息载体是在MapMessage中定义的,从上面的UML图中可以看出,MapMessage中包含的信息有:key和value表示sessionId和session对象,keydata和valuedata表示sessionId和session对象序列化为字节流后的数据,primary表示该会话的源节点,nodes表示该会话的备份节点,msgtype表示操作类型,其定义如下:

这里每个值都代表一个语义,例如MSG_BACKUP表示让接收方把接收到的会话对象进行备份、MSG_REMOVE则表示让接收方按照接收到的会话id把对应的会话删除等等
比如在备份操作中MapMessage对象就像组成一个句子:“本人会话id为keydata,会话值为valuedata,我的源节点为primary,我现在需要做备份操作”。
4、 AbstractReplicatedMap类实现了map接口,通过实现map接口的相关操作达到会话的跨节点操作,它实现了MembershipListener接口,表示可以支持集群节点的添加和删除时,可以相应的更新本集群节点上的session集合;它实现了ChannelListener,可以在接收到集群消息时更新session集合;它实现了RpcCallback,可以在对rpc调用时根据消息操作类型更新session集合;
5、 AbstractReplicatedMap.mapMembers存储了集群成员和他最近一次心跳成功的时间,对于超过指定时间(这个值默认是5秒)之内没有心跳成功的集群节点,将会从集群节点中删除,代码如下:

6、 AbstractReplicatedMap也是基于Tribes组件的,因此包含了成员变量channel,而rpcChannel则是用于rpc调用时的组件,也可以在接收到其他节点的rpc调用时进行相应的处理;currentNode是用于选取会话的备份节点时用的变量,表示上一次刚刚选取的备份节点的序号,选取备份节点时的代码如下:

7、 backupmanager在每次请求结束时,都会调用AbstractReplicatedMap的replicate方法将当前会话的变更信息复制到备份节点,发送的消息是一个MapMessage对象,分为3类消息:新会话、会话更新和会话访问,此外,Map的移除也会向备份节点发送MapMessage消息;AbstractReplicatedMap类的replyRequest、leftOver、messageReceived方法中针对不同类型的消息作出不同的响应,比如说MSG_START类型的消息,是一个集群节点在启动后广播给集群中其他节点的消息,在replyRequest、leftOver、messageReceived方法中分别针对这个类型的调用mapMemberAdded方法,mapMemberAdded的职责就是更新mapMembers中指定集群节点上次心跳成功的时间值和对会话列表中没有备份节点的的会话重新选取一个备份节点;代码如下:

8、 LazyReplicatedMap.publishEntryInfo的职责是给会话选择一个备份节点,并给备份节点发送一个MSG_BACKUP的消息和给代理节点发送一个MSG_PROXY的消息,代码如下:

9、 BackupManager的实现相对比较简单,在startInternal中创建LazyReplicatedMap的对象,并使用这个对象管理会话:

10、 AbstractReplicatedMap.put方法将会话存入innerMap中,流程如下:
  a) 实例化MapEntry,将key和value传入,并设置源节点为目前节点。
  b) 判断本地内存是否已包含key,如是则不仅要本地remove掉,还要跨节点remove。
  c) 通过Round robin算法从MapMember中选择一个作为备份节点。
  d) 实例化一个包含MSG_BACKUP标识的MapMessage对象并发送给备份节点。
  e) 实例化一个包含MSG_PROXY标识的MapMessage对象并发送给除了备份节点外的其他(代理)节点。
  f) put进本地innerMap缓存。

代码如下:

11、 AbstractReplicatedMap.get在指定节点上获取会话,流程如下:
  a) 获取本地的MapEntry对象,它或许直接包含了会话对象,或许包含了会话对象的存放位置信息。
  b) 判断本节点是否属于源节点,如为源节点则直接获取MapEntry对象里面的会话对象并返回。
  c) 判断本节点是否属于备份节点,若为备份节点则直接获取MapEntry对象里面的会话对象作为返回对象,并且还要将本节点升为源节点、重新选取一个新备份节点,把MapEntry对象拷贝到新备份节点。
  d) 判断本节点是否属于代理节点,若为代理节点则向其他节点发送会话对象拷贝请求,“集群中谁有此会话对象请发送给我”,把接收到的会话对象放到本节点并作为返回对象,最后将本节点升为源节点。

代码如下:

12、 AbstractReplicatedMap.remove删除会话对象,流程如下:
  a) 删除本地此MapEntry对象。
  b) 广播其他节点删除此MapEntry对象。

代码如下:

tomcat源码阅读之BackupManager的更多相关文章

  1. Tomcat源码阅读(二)初始化

    近来,我开始阅读tomcat的源码,感觉还挺清晰易懂:为了方便理解,我参考了网上的一些文章,把tomcat的组成归纳一下:整个tomcat的组成如下图所示: Tomcat在接收到用户请求时,将会通过以 ...

  2. tomcat源码阅读

    1      工具准备 需要SVN.Maven.JDK.Eclipse.Eclipse M2插件 2      下载源码及发布包 源码在这里:http://svn.apache.org/repos/a ...

  3. tomcat源码阅读之过滤器

    一.Servlet过滤器: 1.介绍: Servlet过滤器本身并不生成请求和响应对象,它只提供过滤作用. Servlet过滤器能够在Servlet被调用之前检查Request对象,修改Request ...

  4. tomcat源码阅读之SingleThreadModel

    一.接口简介: 实现了SingleThreadModel接口的servlet类只能保证在同一时刻,只有一个线程执行该servlet实例的service方法,在tomcat实现中会创建多个servlet ...

  5. tomcat源码阅读之载入器(Loader)

    一.Java类的载入器: 双亲委派模型: 1.JVM提供了三种类型的类加载器:引导类载入器(bootstrap class loader).扩展类载入器(extension class loader) ...

  6. tomcat源码阅读之集群

    一. 配置: 在tomcat目录下的conf/Server.xml配置文件中增加如下配置: <!-- Cluster(集群,族) 节点,如果你要配置tomcat集群,则需要使用此节点. clas ...

  7. tomcat源码阅读之安全机制

    一.领域(Realm): 1.Principal接口代表角色信息,包含了三个成员:用户名.密码.role列表(以逗号分隔),对应了tomcat-users.xml文件中一行user信息: Generi ...

  8. tomcat源码阅读之默认连接器

    默认连接器 一.UML图: 1.所有的连接器都要实现Connector接口,必须创建Request对象和Response对象,httpConnector作为默认连接器,肯定也是要实现Connector ...

  9. tomcat源码阅读之部署器

    我们知道web应用是用Context实例表示的,而Context是部署到Host实例中的,因此tomcat的部署器是关联的Host实例.Context实例可以用WAR文件部署,也可以把整个web应用的 ...

随机推荐

  1. Spring学习五(JDBC支持)

    Spring的jdbc支持 1配置db.properties,将有关JDBC的信息载入 2bean文件配置数据源,这里用e3p0作为数据源载入db.properties 3配置template的bea ...

  2. JavaScript和它父亲的故事

    附赠脱单秘籍:了解一些JavaScript的历史,聊天的时候说不好可以获得更多程序员小妹子的崇拜的哟~ ๑乛◡乛๑~ 阅读本文可以让你更好的理解什么是ECMAScript. 本次文章内容来自:< ...

  3. MySQL:MySQL Workbench的使用

    MySQL Workbench 一.布局介绍 附:图片转自https://blog.csdn.net/qq_19891827/article/details/53995079 二.创建数据库 第一步: ...

  4. Nginx日志和http模块相关变量

    $arg_PARAMETER #HTTP 请求中某个参数的值,如/index.php?site=www.ttlsa.com,可以用$arg_site 取得 www.ttlsa.com 这个值. $ar ...

  5. 利用Hackrf One进行GPS定位欺骗制作超级跑马机

    0×00 驾校的困惑 现行规定要求每个学员都必须在驾校练习够规定的学时,才能参加考试,在每台教练车上都安装有计时计程终端,学员刷卡刷指纹后开始累计里程.但是目前中国的很多驾校,存在车少人多的情况,假设 ...

  6. ubatu 安装nodejs npm liveserver

    更新ubuntu软件源 sudo apt-get update sudo apt-get install -y python-software-properties software-properti ...

  7. Day5作业及默写

    1,有如下变量(tu是个元祖),请实现要求的功能 tu = ("alex", [11, 22, {"k1": 'v1', "k2": [&q ...

  8. 使用scrapy ImagesPipeline爬取图片资源

    这是一个使用scrapy的ImagesPipeline爬取下载图片的示例,生成的图片保存在爬虫的full文件夹里. scrapy startproject DoubanImgs cd DoubanIm ...

  9. Centos7修改profile文件后导致vi command not find

    Centos7修改profile文件后导致vi command not find,原因是profile文件没有配置正确,系统就无法找到精确命令了.解决方法: 1.在命令行中输入:export PATH ...

  10. 【Python】多线程-1

    #练习:创建一个线程 from threading import Thread import time def run(a = None, b = None) : print a, b time.sl ...