EJB3在JBoss5内集群探究
EJB3在JBoss5x内集群探究
本文介绍ejb3在jboss5x内集群的基本配置及注意事项,我们主要的目的是在jboss5x内集群ejb3,,然后被客户端(可以是web应用程序),不涉及到jboss http请求集群内容。具体见下:
一、 程序准备
我们准备两个项目ejb.rar、webapp.war,其中前者是ejb3项目、后者是web应用程序,主要代码如下:
ejb.rar主要代码:
接口:
package com.sample;
@Remote
//@Local
public interface HelloBeanItf {
public void doSomething();
}
实现:
package com.sample;
import java.io.Serializable;
import javax.ejb.*;
import org.jboss.annotation.ejb.Clustered;
@Stateless
@Clustered
public class HelloBean implements HelloBeanItf {
int counter = 0;
public void doSomething() {
counter++;
System.out.println("Stateless : Value of counter is " + counter);
}
}
上面是无状态的session bean,注意标注@Clustered是必须的,如果不进行标注那么这个session bean将不会被集群。同样有状态的session bean的集群声明也是这样的,如下:
@Stateful
@Clustered
public class HelloBean2 implements HelloBeanItf,Serializable {
int counter = 0;
public void doSomething() {
counter++;
System.out.println("Stateful : Value of counter is " + counter);
}
}
webapp.war主要代码:
创建index.jsp文件用以调用无状态session bean,在主要代码如下:
<%
public void jspInit () {
try {
HelloBeanItf ejb = null;
InitialContext ctx = new InitialContext();
for(int i=0;i<10;i++){
//ejb = (HelloBeanItf) ctx.lookup("HelloBean/local");
ejb = (HelloBeanItf) ctx.lookup("HelloBean/remote");
}
}
catch (Exception exc) {
exc.printStackTrace();
}
}
ejb.doSomething();
%>
Stateless EJB invoked
创建index2.jsp文件用以调用有状态session bean,在主要代码如下:
<%
public void jspInit () {
try {
HelloBeanItf ejb = null;
InitialContext ctx = new InitialContext();
for(int i=0;i<10;i++){
//ejb = (HelloBeanItf) ctx.lookup("HelloBean2/local");
ejb = (HelloBeanItf) ctx.lookup("HelloBean2/remote");
}
}
catch (Exception exc) {
exc.printStackTrace();
}
}
ejb.doSomething();
%>
Stateful EJB invoked
Classpath下添加jndi.porperties文件,具体如下:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=192.168.1.2:1099, 192.168.1.3:1099
二、 配置jboss
配置jboss要稍微麻烦点,我们在三台机器上分别部署jboss名称分别为jboss1、jboss2、jboss3,对应的ip分别为192.168.1.1、192.168.1.2、192.168.1.3。配置具体步骤如下:
(1) 使jboss能通过ip访问,分别找到jboss2与jboss3安装目录下的文件jboss-home\server\all\deploy\jbossweb.sar\server.xml并打开,把
<Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}" connectionTimeout="20000" redirectPort="8443" />
改为:
<Connector protocol="HTTP/1.1" port="8080" address="0.0.0.0" connectionTimeout="20000" redirectPort="8443" />
(2) 配置jvmRoute,打开jboss2及jboss3内的文件jboss-home\server\all\deploy\jbossweb.sar\server.xml,修改
<Engine name="jboss.web" defaultHost="localhost" >
jboss2改为:<Engine name="jboss.web" defaultHost="localhost" jvmRoute="jboss2">
jboss3改为:<Engine name="jboss.web" defaultHost="localhost" jvmRoute="jboss3">
(3) 设置ServerPeerID,打开jboss2及jboss3内的文件jboss-home\ server\all\deploy\messaging\ messaging-service.xml,修改
<attribute name="ServerPeerID">${jboss.messaging.ServerPeerID:0}</attribute>
jboss2改为:<attribute name="ServerPeerID">${jboss.messaging.ServerPeerID:2}</attribute>
jboss3改为:<attribute name="ServerPeerID">${jboss.messaging.ServerPeerID:3}</attribute>
三、 部署
我们把ejb分别部署到jboss2和jboss3内,使它们进行集群。把web客户端部署到jboss1内用以访问ejb,具体如下:
(1) 复制ejb.jar到jboss2的jboss-home\server\all\farm下,使用all进行部署是因为all内包含所有的服务,集群服务及jboss cache服务都是我们所需的,放入farm内是为了当几个jboss集群后它们将自动完成部署ejb到各自的farm目录内,不过这个功能偶尔会部署失败,可以手工copy一份。当然我们也可以手工把ejb分别复制jboss2、jboss3的jboss-home\server\all\deploy目录下,集群效果一样。
(2) 分别进入jboss2、jboss3主机上控制台进入jboss安装目录使用 run.bat –c all -b 0.0.0.0 命令启动jboss。
当然我们也可以分别用run.bat –c all -b 192.168.1.2 run.bat –c all -b 192.168.1.3分别启动
(3) 部署webapp.war到jboss1的目录jboss-home\server\default\deploy下,并启动jboss1
(4) 部署webapp.war到jboss2的目录jboss-home\server\all\deploy下,用以跟jboss1的web客户端做比对。
四、 运行分析
(1) 运行jboss1内的web客户端
在浏览器上输入http://192.168.1.1/webapp/index.jsp,后我们观察下jboss2、jboss3的控制台
jboss2 |
jboss3 |
Stateless : Value of counter is 1 Stateless : Value of counter is 1 Stateless : Value of counter is 2 Stateless : Value of counter is 2 Stateless : Value of counter is 3 |
Stateless : Value of counter is 1 Stateless : Value of counter is 2 Stateless : Value of counter is 3 Stateless : Value of counter is 4 Stateless : Value of counter is 5 |
再刷新一次如下:
jboss2 |
jboss3 |
Stateless : Value of counter is 3 Stateless : Value of counter is 4 Stateless : Value of counter is 4 Stateless : Value of counter is 5 Stateless : Value of counter is 5 |
Stateless : Value of counter is 6 Stateless : Value of counter is 7 Stateless : Value of counter is 8 Stateless : Value of counter is 9 Stateless : Value of counter is 10 |
第一次访问时我们循环了10次,发现在jboss上分别运行了5次,这就达到了负载均衡的目的。第二次访问了我们看jboss内counter是的规律是11223344…这说明jboss1内产生了两个HelloBean 的实例进行轮训访问,而jboss2内只有一个HelloBean 的实例,这完全符合无状态session bean的特性,至于为什么jboss2内有两个实例,还未搞清楚,有待探究。
然后我们在浏览器内输入http://192.168.1.1/webapp/index2.jsp,后我们观察下jboss2、jboss3的控制台
jboss2 |
jboss3 |
|
Stateful : Value of counter is 1 Stateful : Value of counter is 2 Stateful : Value of counter is 3 Stateful : Value of counter is 4 Stateful : Value of counter is 5 Stateful : Value of counter is 6 Stateful : Value of counter is 7 Stateful : Value of counter is 8 Stateful : Value of counter is 9 Stateful : Value of counter is 10 |
再刷新一次如下:
jboss2 |
jboss3 |
Statefu l: Value of counter is 1 Stateful : Value of counter is 2 Stateful : Value of counter is 3 Stateful : Value of counter is 4 Stateful : Value of counter is 5 Statefu l: Value of counter is 6 Stateful : Value of counter is 7 Stateful : Value of counter is 8 Stateful : Value of counter is 9 Stateful : Value of counter is 10 |
|
如再连续刷新两次发现输入跟上面一样。第一次访问时我们循环了10次,发现在jboss3上分别运行了10次产生了一个HelloBean2实例,第二次jboss2上运行10次产生了一个HelloBean2实例,这样我们可以看出,每次访问时集群会随机给我们找一个ejb服务,而每次访问都会产生一个新的session bean实例,这完全符合有状态session bean的特性。
(2) 关闭jboss3,我们按照上一步操作进行,发现访问正常进行,所有的请求都在jboss2上响应了,这样我们就达到了故障转移的目的。
(3) 以同样的方式重新启动jboss3,我们分别通过http://192.168.1.2/webapp/index.jsp,http://192.168.1.2/webapp/index2.jsp,进行访问,不难发现所有的请求都在jboss2上得到了响应,这是因为如果如果jboss内的web客户端访问集群ejb时,如果要访问的ejb集群本机也参与的话那么群集只返回本机的ejb,当然如果本机的ejb挂掉的话集群是可以随机分配其它jboss内的ejb的。
(4) 我们可以把HelloBeanItf 的注解改为@Local,把index.jsp、index2.jsp内的 ctx.lookup("HelloBean2/remote"); 改为 ctx.lookup("HelloBean2/local");然后按照之前方式重新部署,我们发现只能通 http://192.168.1.2/webapp/index.jsp,http://192.168.1.2/webapp/index2.jsp进行访问,而且请求全部在jboss2上响应,这也符合Local的session bean的特性。
五、讨论
通过上面的测试我们可以想象,我们可以构造这样一个集群系统,在一个jboss内构建对外的web客户端来访问其它多个集群后的ejb服务的系统是完全可行的,这样要求这个对外web客户端的jboss不能参与ejb的集群。这种方式看上去有点类似于apache+mod_jk+jboss的http集群,但本质上是不太一样的。这两种方式的集群到底哪个更优本人还未进行过测试,希望以后能有机会亲自测试体验下。以上是我对jboss内集群ejb的一些探究,不足与错误忘大家指点。