EJB 的集群表现为两个方面,负载平衡和失败转发,在 Weblogic Server 中可以轻松得通过部署描述符来设置 EJB 的集群策略。
Weblogic Server 提供了常用的几种负载平衡算法,如轮循法、加权法、随机法、轮循关系法、基于加权关系法、随机关系法等,并 且用户还可以自定义负载平衡算法,只需要实现 weblogic.rmi.cluster.CallRouter 接口。Weblogic Server 中采用副本识别存根(Replica-Aware Stubs),提供了两种副本识别存根,一个是 EJBHome 接口,另一个是 EJBObject 接口,这样 Weblogic Server可以从这两层获得负载平衡和失败转发,一层是当客户端通过 EJBHome 存根查找 EJB 对象,另一层是当客户端通过 EJBObject 存根调用 Bean 类的业务方法的时候,也就是我们前面提到的远程 Home 存根实现集群和远程存根实现集群。存根是一种智能对象,具 有网络协议感知能力,与服务器通信处理客户的请求,能够知道集群中同一个对象的不同实例所在的服务器节点;并且能够进行故障 转发,即当存根请求的一台服务器出现了故障,其能够将请求转发到另外一台服务器上。
1.无状态会话 Bean 的集群
无状态会话 Bean 不保存与特定客户端的任何状态,所有的无状态会话 Bean 的实例都被看作是等同的。所以对于无状态会话 Bean,可以在远程 Home 存根和远程存根两个地方进行负载平衡。EJB 对象发送存根到客户端,客户端获取的这些存根可以是已经集群的, 也可以是没有集群的。对于集群的服务,存根根据负载均衡和容错的不同需求调用集群中合适的服务器;而对没有集群的服务,所有 对此存根的调用只能由提供此服务的服务器来处理。这可以通过部署描述符中的<stateless-bean-is-clusterable>来设置,如果属 性设置为 true,则 EJB 对象是可集群的,如果属性为 false 则是不可集群的。Weblogic Server 中可以根据集群的不同情况选择不 同的负载平衡算法,部署描述符中的<stateless-bean-load-algorithm>设置具体的负载平衡算法,可选的属性有 round-robin、 random、weight-based;Weblogic Server 支持自己编写的负载平衡算法,需要实现 weblogic.rmi.cluser.CallRouter 接口, 并在部署描述符<stateless-bean-call-router-classname>中指定自己编写的负载平衡算法的类名。
无状态会话 Bean 的失败转发将客户端调用的幂等(idempotent)的业务方法转移到另外的一台服务器上进行执行。幂等的方法是指重复的应用程序调用有一个应用程序的相同的效果,即 f(f(x))=f(x)。考虑如下的两个业务方法,查询学生成绩(命名为 h(x))和 修改学生成绩(命名为 g(x)),前者用于查询某一学生某一门课程的成绩,后者用于对某一学生的某一门课程的成绩增加 5 分。
客户 端将请求发送给存根,存根首先请求 Server a,结果遇到了错误被返回,然后请求 Server b 进行执行。业务方法的失败可能是在如下情况下发生的,但存根不知道是如下情形中的那一种:
·存根发送的请求还没有到 Server a,就遇到了错误返回
·方法全部正确的执行,但在返回给客户端的时候遇到了网络错误
如果是第一种情形,有 h(h(x))=h(x),g(g(x))=g(x)。两个方法都可以被存根转发到 Server b 上进行执行,然后返回给客户;但 第二种情形,有 h(h(x))=h(x),g(g(x))≠g(x)。查询学生成绩的方法可以顺利的执行,因为该方法没有修改数据,调用多次返回的 值都是相同的,修改学生成绩的方法就可能出现异常,因为第一次执行时候已经成功修改了成绩,只是返回给客户端的时候因为网络错误造成的请求没有完成,当方法被转发到 Server b 上执行的时候,该学生的课程成绩又被增加了 5 分,这明显是错误的。所以为 了保证无状态会话 Bean 的失败转发机制是有效的,其业务方法应该是幂等的,如果对不是幂等的方法也希望进行失败转发,那么应 把这些方法设计到一个状态会话 Bean 中。为此在设计无状态会话 Bean 的失败转发的时候要充分考虑业务方法的幂等性,为了最大程度的利用失败转发功能,应尽可能的在业 务级别保证方法的幂等性。Weblogic Server 在部署描述符中提供了<idempotent-method>来指定幂等的方法,存根仅对这些方法进行失败转发。
2.有状态会话 Bean 的集群
有状态会话 Bean 保存和客户端之间交谈的状态。他的集群只能在远程 Home 存根上进行,因为所有的 EJB home 接口都是无状态 的;但对于远程存根无法进行负载平衡,因为每个客户一次只有一个 bean 实例时活动的,也就是说,客户需一直和一个特定的 bean实例进行交互。有状态会话 Bean 在方法级别上的失败转发需要不同服务器间的状态复制,因为有状态会话 Bean 的另一个实例不会 自动获得在原来 bean 实例上存在的交谈状态,为了实现有状态会话 Bean 的失败转发,需要将有状态会话 bean 实例复制到备份服务器上。
Weblogic Server 中提供了主服务器和辅助服务器的概念来满足有状态会话 Bean 的状态复制。当服务器接收到创建有状态会话 bean实例的请求时,创建了实例并从复制组中确定辅助服务器来为 bean 实例提供失败转发策略。复制组是一组逻辑上相关的服务器,主服务器从复制组或优先复制组中选择等级最小的服务器作为辅助服务器,然后将主服务器和辅助服务器的相关信息添加到存根程序,存根程序被客户端下载到本地,这样当客户端的业务方法调用失败之后,存根程序会自动的转移业务方法到辅助服务器上进行执行。 主服务器选择辅助服务器的规则如表 3-2 所示。
表 3-2 主服务器选择辅助服务器的规则
服务器是否是主服务器的优先 服务器是否与主服务器驻留在
服务器的等级 复制组 不同的物理机器上
1 是 是
2 是 否
3 否 是
4 否 否
失败转发前状态复制的示意图如图 3-10 所示。
图 3-10 失败转发前状态复制图集群 实例 X Server A Server B Server C 实例 X 的存根主服务器:A 辅助服务器:B 客户端 服务器间复制实例 X 的状态
主服务器 辅助服务器 复制 X 的状态 交互
客户端开始与主服务器 Server A 进行交互,Server B 是按照表 3-2 选择 Server A 的辅助服务器,客户端与 Server A 的交谈状态 信息被复制到 Server B 中,Weblogic Server 采用只复制客户
端与 bean 实例间交谈的状态信息来节省服务器的资源。状态复制通常在如下的两种情况下发生:
·客户端对主服务器 Server A 上的调用是事务性的,则在事务结束后复制
·客户端对主服务器 Server A 上的调用是非事务性的,则在每个方法调用之后复制
失败转发后状态复制的示意图如图 3-11 所示。当客户当前的调用被异常返回,存根就会请求辅助服务器来完成请求。此时,原来的 辅助服务器 Server B 变成了主服务器,利用原来从 Server A 中复制的信息新建一个 bean 实例恢复对话。根据表 3-2 中的辅助服 务器选择策略选择 Server C 作为新的辅助服务器,并将状态信息复制到 Server C 中。之后,客户端的存根被更新,保存新的主服 务器 Server B 和辅助服务器 Server C 的信息,以备 Server B 发生失败时进行新的失败转发。
图 3-11 失败转发后状态复制图集群 实例 X Server A Server B Server C 实例 X 的存根主服务器:B 辅助服务器:C 客户端 服务器间复制实例 X 的状态
主服务器 辅助服务器 复制 X 的状态 交互 服务器故障
3.实体 Bean 的集群
实体 Bean 通常不能够被装载平衡和失败转发。在实际的企业级应用开发中,由于采用会话外观模式,实体 Bean 总是被会话 Bean包装,在会话 Bean 中采用本地接口访问实体 Bean,客户端从不应该通过远程接口访问实体 Bean,因此对实体 Bean 的集群没有任何的意义。