概述
本文分两个部分:有状态会话Bean集群和有状态会话Bean集群示例
有状态会话Bean集群
关于有状态会话Bean集群的基本理论参照 JBoss 7/WildFly 集群之无状态会话Bean集群 - I(基本理论)。有状态会话Bean集群示例
有状态会话Bean集群示例架构如下图:
如图:
- JBoss node1和node2组成一个集群,node1对应IP地址10.66.218.46,node2对应IP地址10.66.218.47
- EJB 客户端位于另一台机器
定义StatefulSession接口
public interface StatefulSession {
public String getServer();
public String getName();
public void setName(String name);
}
定义StatefulSession接口实现
@Stateful
@Remote(StatefulSession.class)
@Clustered
public class StatefulSessionBean implements StatefulSession {
public String getServer() {
StringBuffer sb = new StringBuffer();
String ip = System.getProperty("jboss.bind.address");
if(null != ip) {
sb.append("jboss.bind.address: " + ip);
sb.append(", jboss.node.name: ");
}
String jbossNodeName = System.getProperty("jboss.node.name");
if(null != jbossNodeName) {
sb.append(jbossNodeName);
}
String result = sb.toString();
System.out.println(result);
return result;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
启动并部署有状态会话Bean集群应用
EJB远程调运我们需要创建Application User,具体执行JBOSS_HOME/bin/add_user.sh或JBOSS_HOME/bin/add_user.bat创建Application User democlient/password1!
我们使用如下命令分别启动两个JBoss节点:
./standalone.sh -c standalone-ha.xml -b 10.66.218.46 -bmanagement=10.66.218.46 -u 239.255.100.100 -Djboss.node.name=node1
./standalone.sh -c standalone-ha.xml -b 10.66.218.47 -bmanagement=10.66.218.47 -u 239.255.100.100 -Djboss.node.name=node2
有状态会话Bean集群应用代码位于: https://github.com/kylinsoong/cluster/tree/master/demo/sfsb
我们可以使用软件安装及资料下载中描述的方法下载,编译生成部署包cluster-demo-sfsb.jar。使用使用4种方式部署应用到JBoss7/WildFly中描述的方法分别部署cluster-demo-sfsb.jar到两个JBoss节点。
定义EJB客户端
EJB客户端配置文件jboss-ejb-client.properties内容如下:
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=node1,node2
remote.connection.node1.host=10.66.218.46
remote.connection.node1.port=4447
remote.connection.node1.connect.timeout=500
remote.connection.node1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.node1.username=democlient
remote.connection.node1.password=password1!
remote.connection.node2.host=10.66.218.47
remote.connection.node2.port=4447
remote.connection.node2.connect.timeout=500
remote.connection.node2.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.node2.username=democlient
remote.connection.node2.password=password1!
remote.clusters=ejb
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.username=democlient
remote.cluster.ejb.password=password1!
EJB客户端调运类如下:
public class StatefulSessionBeanClient {
private String applicationContext = "cluster-demo-sfsb";
private String SFSB_JNDI = "ejb:/" + applicationContext + "/StatefulSessionBean!" + StatefulSession.class.getName() + "?stateful";
private void execute() throws Exception {
Hashtable<String, String> jndiProps = new Hashtable<String, String>();
jndiProps.put( Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming" );
Context context = new InitialContext( jndiProps );
StatefulSession sfsb = (StatefulSession)context.lookup(SFSB_JNDI);
System.out.println("Sticky routes Test");
for(int i = 0 ; i < 10 ; i ++){
System.out.println(sfsb.getServer());
}
System.out.println("\nFail Over Test");
for(int i = 0 ; i < 10 ; i ++) {
System.out.println(sfsb.getName());
sfsb.setName("sfsb-test-" + i);
Thread.currentThread().sleep(1000 * 5);
}
}
public static void main(String[] args) throws Exception {
new StatefulSessionBeanClient().execute();
}
}
运行StatefulSessionBeanClient输出如下:
Sticky routes Test
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
jboss.bind.address: 10.66.218.46, jboss.node.name: node1
Fail Over Test
null
sfsb-test-0
sfsb-test-1
sfsb-test-2
sfsb-test-3
sfsb-test-4
sfsb-test-5
sfsb-test-6
sfsb-test-7
sfsb-test-8
我们看到同一个EJB Client通过相同的client stub的一系列EJB调运会进行Sticky 转发,即所有请求都分配到节点1。当 sfsb-test-3输出后我们手动关闭节点1,我们发现sfsb-test-4,sfsb-test-5...输出,查看JBoss日志我们可以发现有状态会话Bean集群中容错和状态同步机制。