java org.jgroups.Version
The JGroups tutorial原文地址: http://jgroups.org/tutorial/index.html 本站备份: http://javaarm.com/file/opensource/jgroups/jgroups-tutorial_2014-10-15.zip 实例代码: http://javaarm.com/file/opensource/jgroups/jgroups-tutorial_2014-10-15_study/com.ybxiang.SimpleChat.java (YBXIANG稍加改写:每隔8秒自动发送一次消息,不需要手工输入消息了)
链接
| 主题↑
| 回复↓
|
1. ybxiang
2014-10-15 发送消息
Table of Contents1. 安装1.1. 下载 1.2. 配置 1.3. 测试你的设置 1.4. 运行一个演示程序 1.5. 在没有网络的情况下使用JGroups 1.6. 故障解答 2. 编写一个简单的应用程序 2.1. JGroups概述 2.2. 创建一个信道并加入一个集群 2.3. 主事件循环以及发送聊天信息 2.4. 接收消息并查看变化通知 2.5. 试试 SimpleChat 应用程序 2.6. Extra credits: 维护共享的集群状态 2.7. 总结 Copyright Red Hat 1998 - 2015 本文档的许可证为 "Creative Commons Attribution-ShareAlike (CC-BY-SA) 3.0" 许可证.
关于该教程
这是一份关于如何安装JGroups以及编写一个简单应用程序的简短教程。其目的是展示如何配置JGroups以及编写一个展示JGroups API的主要方法的应用程序。 Bela Ban, Kreuzlingen, Switzerland, 2014年8月。
链接
| 主题↑
| 回复↓
|
2. ybxiang
2014-10-15 发送消息
1. 安装1.1. 下载JGroups可以从 这里 下载。对于本教程,我使用的是JGroups 3.0的二进制版本,因此请下载一个 jgroups-3.x.y.jar 文件 (比如 jgroups-3.0.0.Final.jar)。 该JAR文件包含了:
1.2. 配置
|
3. ybxiang
2014-10-15 发送消息
2. 编写一个简单的应用程序本章的目的是编写一个简单的基于文本的聊天程序 (SimpleChat),具有下面的功能特征:
2.1. JGroups概述JGroups使用JChannel作为其主要API,用于 连接到集群、发送/接收消息,以及注册监听器,当某些事情(比如成员加入)发生时就会调用这些监听器。 发送出去的是Message,它包含了一个byte buffer (负载),加上发送者和接收者的地址。地址是org.jgroups.Address的子类,通常包含一个IP地址加上一个端口。 在集群中的JGroups实例列表叫做一个视图(View),每个JGroups实例都包含完全相同的视图。可以通过调用View.getMembers()来得到所有JGroups实例的地址的一个列表。 JGroups实例只能在它们加入集群之后才能发送或接收消息。 当一个JGroups实例想要离开集群的时候,可以调用方法JChannel.disconnect()或者JChannel.close()。如果信道依旧连在集群上的话,在关闭该信道之前,后者实际上调用disconnect()。 2.2. 创建一个信道并加入一个集群要想加入一个集群,我们将使用一个JChannel。我们可以通过一个定义了信道属性的配置(比如一个XML文件)来创建JChannel的实例。要想实际地连接到集群上,那么使用 connect(String clustername)方法。所有用相同参数调用connect()方法的 channel实例 都会加入相同的集群。因此,让我们实际地创建一个JChannel并连接到一个叫做"ChatCluster"的集群上:
首先,我们利用无参数的构造函数创建了一个信道。这将会用默认的属性来配置该信道。此外,我们也可以传递一个XML文件来配置该信道,比如new JChannel("/home/bela/udp.xml")。 connect() 方法会加入集群"ChatCluster"。请注意,我们不需要预先明确地创建一个集群;如果它是第一个实例的话,connect()方法就会创建该集群。所有加入相同集群的实例都位于相同的集群中,比如如果我们让
,那么,我们就有3个集群:"cluster-one"具有实例 ch1和ch4,"cluster-two"具有ch2和ch3,"cluster-three"只有ch5。
链接
| 主题↑
| 回复↓
|
4. ybxiang
2014-10-15 发送消息
2.3. 主事件循环以及发送聊天信息我们现在运行一个事件循环,该循环会从stdin读取输入 (一条消息),然后将输入信息发送给当前处于集群中的所有实例。当输入"exit" 或 "quit" 时,我们退出该循环,然后关闭该信道。
我们将 eventLoop() 以及信道关闭语句 添加到 start() 方法中,这样我们就提供了 eventLoop 的一个实现。 这个事件循环会阻塞着,直到输入了新的一行数据 (来自标准输入),然后发送一条消息到该集群。发送消息是通过创建一条新的消息然后以该消息作为参数调用Channel.send()方法来完成的。 Message的构造函数的第一个参数是发送目标的地址。空的目标地址将会导致 消息被发送到集群中的每个节点 (某个JGroups实例的非空地址 会导致 该消息只发送给该JGroups实例)。 第二个参数是我们自己的地址。这里也是空的,因为协议栈总是会插入正确的地址。 第三个参数是我们从stdin读取的数据行,Message会使用Java serialization来创建一个 byte[] buffer,然后将其设置为消息的负载。 请注意,我们也可以自己序列化被发送数据对象 (实际上,这是推荐的方式!) 并使用第三个参数是一个byte[] buffer的Message构造函数。 现在该应用程序功能完备了,除了我们还不能接收消息或查看通知之外。我们将在下一节完成。 2.4. 接收消息并查看变化通知现在,让我们注册一个 Receiver 来接收消息并查看变化。为了达到该目的,我们本例可以实现 org.jgroups.Receiver,然而,我选择了扩展 ReceiverAdapter,它带有默认的实现,我们只需要覆写我们感兴趣的回调方法(receive()和viewChange())既可。现在, 我们需要扩展ReceiverAdapter:
,然后在
,然后实现
当有任何一个新的JGroups实例加入该集群或者一个现有的JGroups实例离开(包括崩溃)该集群时,这个viewAccepted()回调 方法就会被调用。View的toString()方法会打印出 view ID (一个递增的ID)以及在该集群中的JGroups实例的一个列表。 在 receive() 回调方法中,我们得到一个作为参数传入的Message。我们只是将其buffer作为一个对象 (再一次,使用了Java serialization),然后将其打印到 stdout。我们也打印出了发送者的地址(Message.getSrc())。 注意,我们也可以通过调用 Message.getBuffer() 来得到该 byte[] buffer (负载),然后我们自己反序列化,比如 String line=new String(msg.getBuffer())。 YBXIANG: 关于序列化和反序列化 (a)请参见下面的文章:
链接
| 主题↑
| 回复↓
|
5. ybxiang
2014-10-15 发送消息
2.5. 试试 SimpleChat 应用程序Now that the demo chat application is fully functional, let’s try it out. Start an instance of SimpleChat: [linux]/home/bela$ java SimpleChat ------------------------------------------------------------------- GMS: address=linux-48776, cluster=ChatCluster, physical address=192.168.1.5:42442 ------------------------------------------------------------------- ** view: [linux-48776|0] [linux-48776] > The name of this instance is linux-48776 and the physical address is 192.168.1.5:42442 (IP address:port). A name is generated by JGroups (using the hostname and a random short) if the user doesn’t set it. The name stays with an instance for its lifetime, and maps to an underlying UUID. The UUID then maps to a physical address. We started the first instance, let’s start the second instance: [linux]/home/bela$ java SimpleChat ------------------------------------------------------------------- GMS: address=linux-37238, cluster=ChatCluster, physical address=192.168.1.5:40710 ------------------------------------------------------------------- ** view: [linux-48776|1] [linux-48776, linux-37238] > The cluster list is now [linux-48776, linux-37238], showing the first and second instance that joined the cluster. Note that the first instance (linux-48776) also received the same view, so both instances have the exact same view with the same ordering of its instances in the list. The instances are listed in order of joining the cluster, with the oldest instance as first element. Sending messages is now as simple as typing a message after the prompt and pressing return. The message will be sent to the cluster and therefore it will be received by both instances, including the sender. When "exit" or "quit" is entered, then the instance will leave the cluster. This means, a new view will be installed immediately. To simulate a crash, simply kill an instance (e.g. via CTRL-C, or from the process manager). The other surviving instance will receive a new view, with only 1 instance (itself) and excluding the crashed instance.
链接
| 主题↑
| 回复↓
|
6. ybxiang
2014-10-15 发送消息
2.6. Extra credits: 维护共享的集群状态JGroups的用法之一是维护状态,该状态在集群中进行复制。比如,状态可以是 web server中的HTTP sessions。如果在集群中复制这些 sessions,那么客户端就能够访问该集群中的任何一台服务器,在为该客户端服务的 session崩溃之后,该user sessions依旧可用(位于集群中的其它节点上)。 任何对一个session的更新都会被复制到整个集群中,比如通过序列化被修改的属性,然后通过JChannel.send()把该修改信息发送到该集群中的每台服务器上。这需要所有的服务器具有相同的状态。 然而,当一台新的服务器启动时,会发生什么事情呢?该服务器必须通过某种方法从该集群中的某台已经存在的服务器上复制状态(比如,所有的HTTP sessions)。这叫做 状态转移。 在JGroups中,状态转移是通过实现2个回调方法(getState()和setState()) 以及 调用 JChannel.getState() 方法来做到的。请注意,为了能够在一个应用程序中使用状态转移功能,协议栈必须包含一个状态转移协议 (该demo应用程序所使用的默认协议栈就是这样)。 现在修改start()方法,让它包含对JChannel.getState()的调用:
这个getState()方法的第一个参数是目标JGroups实例,这里的null意思是从第一个JGroups(协调者)实例获取状态。第二个参数是超时时间;这里,我们准备等待10秒以完成状态转移。如果状态转移没有在这个时间之内完成,那么就会抛出一个异常。0意味着永远等待。 ReceiverAdapter定义了一个回调方法 getState(),通过对一个已存在的JGroups实例(通常是协调者) 调用该方法 来获取集群的状态。在我们的实例应用程序中,我们将状态定义为 聊天会话。这是一个简单的列表,我们每次收到消息都会添加到它的末尾。(请注意,这可能不是最好的关于状态转移的例子,因为状态数据总是在增加的。作为一 个 workaround,我们本可以使用一个带有边界的 list,尽管我们在这里没有这么干)。 该列表被定义为一个实例变量:
当然,现在我们需要修改 receive() 方法来添加每条接收到的消息到我们的状态变量中:
getState()回调方法的实现是 public void getState(OutputStream output) throws Exception { 这个getState()方法在 state provider(也就是一个已经存在的JGroups实例) 中被调用,用以返回共享的集群状态。该方法被传入一个 output stream,以便将state数据写入。请注意,在状态被写入该output stream之后,JGroups会自动关闭该它,即便出现异常也会关闭,因此在这个回调方法中不必关闭该output stream。 由于对 setState()方法在 state requester(也就是调用JChannel.getState()的JGroups实例)端 被调用。它的任务是 从input stream中读取状态,然后做相应的设置:
我们再次调用了JGroups的辅助方法 (Util.objectFromStream()),来从一个input stream中(读取并)创建一个对象。 然后我们对 我们将 接收到的聊天历史中的消息的数量 打印到stdout。请注意,对于一个大型的聊天历史而言,这是行不通的,但是,再一次地,我们本来是可以使用带有边界的聊天历史列表的。 YBXIANG实践:运行 http://javaarm.com/file/opensource/jgroups/jgroups-tutorial_2014-10-15_study/com.ybxiang.SimpleChat.java 步骤:1) 运行com.ybxiang.SimpleChat.java 2) 等待半分钟以上 3) 再次运行com.ybxiang.SimpleChat.java,在1)中运行的SimpleChat不要关闭! 4) 等待大约15秒左右,关闭3)中的SimpleChat 5) 等待大约15秒左右,关闭1)中的SimpleChat 我们用下面的颜色标识这2个SimpleChat发出的消息:
第1个SimpleChat【黑色】的日志如下: -------------------------------------------------------------------第2个SimpleChat【绿色】的日志如下: -------------------------------------------------------------------
链接
| 主题↑
| 回复↓
|
7. ybxiang
2014-10-15 发送消息
2.7. 总结In this tutorial, we showed how to create a channel, join and leave a cluster, send and receive messages, get notified of view changes and implement state transfer. This is the core functionality provided by JGroups through the JGroups has two more areas that weren’t covered: building blocks and the protocol stack. Building blocks are classes residing on top of a JChannel that provide a higher abstraction level, e.g. request-response correlators, cluster-wide method calls, replicated hashmaps and so forth. The protocol stack allows for complete customization of JGroups: protocols can be configured, removed, replaced, enhanced, or new protocols can be written and added to the stack. The code for SimpleChat can be found ./code/SimpleChat.java[here]. Here are some links for further information about JGroups:
YBXIANG: JBoss AS的集群是基于JGroups的,JBoss AS集群是有Master节点的,我相信JBoss AS的Master节点就是JGroups中的协调者节点(参见 |