JGroups(1)

转载自:http://whitesock.iteye.com/blog/199229

 

1 Overview
    JGroups是一个用于建立可靠的组播通信的工具包(这里指的组播并不一定是IP Multicast,JGroups同样支持使用TCP作为传输协议)。其中可靠性是指通过适当的配置可以保证:消息在传输的过程中不会丢失;所有的接收者以相同的顺序接受所有的消息;原子性:一个消息要么被所有的接收者接收,要么不被任何一个接收者都接收。目前在JBoss Application Server Clustering,OSCache Clustering,Jetty HTTP session replication,  Tomcat HTTP session replication中都使用了JGroups。

  Unreliable Reliable
Unicast UDP TCP
Multicast IP Multicast JGroups

    TCP和UDP是单播(Unicast)协议,也就是说:发送者和每一接收者之间是点对点传输。 如果一个发送者希望向多个接收者传输相同的数据,那么必须相应的复制多份数据。TCP是可靠的传输协议,但UDP不是可靠的,也就是说报文在传输的过程中可能丢失、重复或着乱序,报文的最大尺寸也有限制。IP Multicast可以将消息同时发送到多个接收者。由于IP Multicast是基于UDP的,因此IP Multicast是不可靠的。IP Multicast需要一个特殊的组播地址,它是一组D类IP地址,范围从224.0.0.0 到 239.255.255.255,其中有一部分地址是为特殊的目的保留的。JGroups使用UDP (IP Multicast)、TCP、JMS作为传输协议。JGroups最强大的功能之一是提供了灵活的,可定制的协议栈,以满足不同的需求。例如,如果选择使用IP Multicast作为传输协议,那么为了防止报文丢失和重复,可以在协议栈中添加NAKACK协议;为了保证报文的顺序,可以在协议栈中添加TOTAL协议,以保证FIFO的顺序;为了在组内成员发生变化时得到通知和回调,可以添加Group Membership Service (GMS) 和 FLUSH协议;Failure Detector (FD)协议用于识别组内崩溃的成员;如果新加入的成员希望获得组内其它成员维护的状态,那么可以向协议栈中添加STATE_TRANSFER协议;如果希望对传输的数据进行加密,那么可以使用CRYPT协议等等。

    JGruops的主要功能有:

  • 组的创建和删除。组可以跨越LANs或者WANs。
  • 加入组、主动或者被动(例如当机或者网络故障)离开组。
  • 在组成员改变时,组中其它成员可以得到通知。
  • 向组中的单个或者多个成员发送消息。

    在JGroups中JChannel类提供了主要的API ,用于连接到集群(cluster)、发送和接收消息(Message)和注册listeners等。Message包含消息头(保存地址等信息)和一个字节数组(保存希望传输的数据)。org.jgroups.Address接口及其实现类封装了地址信息,它通常包含IP地址和端口号。连接到集群中的所有实例(instance)被称为一个视图(org.jgroups.View)。通过View.getMembers()可以得到所有实例的地址。实例只有在连接到集群后才能够发送和接收消息。以相同name调用JChannel.connect(String name)方法的所有实例会连接到同一个集群。当实例希望离开集群时,可以调用JChannel.disconnect()方法。当希望释放占有的资源时,可以调用JChannel.close()方法。JChannel.close()方法内部会调用JChannel.disconnect()方法。
    通过调用JChannel.setReceiver()方法可以接收消息和得到View改变的通知。每当有实例加入或者离开集群的时候,viewAccepted(View view)方法会被调用。View.toString()方法会打印出View中所有实例的地址,以及View ID。需要注意的是,每次viewAccepted(View view)方法被调用时,view参数都不同,其View ID也会增长。View内的第一个实例被称为coordinator。Receiver接口上的getState(),setState()方法用于在实例间传递状态。新的实例通过setState()方法获得通过状态,而这个状态是通过调用集群中其它某个实例上的getState()获得的。

    以下是JGruops manual中的一个简单的例子:

Java代码   收藏代码
  1. import java.io.BufferedReader;  
  2. import java.io.InputStreamReader;  
  3. import java.util.LinkedList;  
  4. import java.util.List;  
  5.   
  6. import org.jgroups.JChannel;  
  7. import org.jgroups.Message;  
  8. import org.jgroups.ReceiverAdapter;  
  9. import org.jgroups.View;  
  10. import org.jgroups.util.Util;  
  11.   
  12. public class SimpleChat {  
  13.     //  
  14.     private JChannel channel;  
  15.     private List<String> state = new LinkedList<String>();  
  16.     private String userName = System.getProperty("user.name""WhiteSock");  
  17.       
  18.     public void start() throws Exception {  
  19.         //  
  20.         channel = new JChannel();  
  21.         channel.setReceiver(new ReceiverAdapter() {  
  22.               
  23.             public void receive(Message msg) {  
  24.                 System.out.println(msg.getSrc() + ": " + msg.getObject());  
  25.                   
  26.                 synchronized(state) {  
  27.                     state.add((String)msg.getObject());  
  28.                 }  
  29.             }  
  30.               
  31.             public void viewAccepted(View view) {  
  32.                 System.out.println("view accepted: " + view);  
  33.             }  
  34.               
  35.             public byte[] getState() {  
  36.                 synchronized(state) {  
  37.                     try {  
  38.                         return Util.objectToByteBuffer(state);  
  39.                     }  
  40.                     catch(Exception e) {  
  41.                         e.printStackTrace();  
  42.                         return null;  
  43.                     }  
  44.                 }  
  45.             }  
  46.               
  47.             @SuppressWarnings("unchecked")  
  48.             public void setState(byte[] new_state) {  
  49.                 try {  
  50.                     List<String> list=(List<String>)Util.objectFromByteBuffer(new_state);  
  51.                     synchronized(state) {  
  52.                         state.clear();  
  53.                         state.addAll(list);  
  54.                     }  
  55.                     System.out.println("received state (" + list.size() + " messages in chat history):");  
  56.                     for(String str: list) {  
  57.                         System.out.println(str);  
  58.                     }  
  59.                 }  
  60.                 catch(Exception e) {  
  61.                     e.printStackTrace();  
  62.                 }  
  63.             }  
  64.         });  
  65.         channel.connect("ChatCluster");  
  66.         channel.getState(null10000);  
  67.           
  68.         //  
  69.         sendMessage();  
  70.           
  71.         //  
  72.         channel.close();  
  73.     }  
  74.       
  75.     private void sendMessage() throws Exception {  
  76.         boolean succeed = false;  
  77.         BufferedReader br = null;  
  78.         try {  
  79.             br = new BufferedReader(new InputStreamReader(System.in));  
  80.             while(true) {  
  81.                 System.out.print(">");  
  82.                 System.out.flush();  
  83.                 String line = br.readLine();  
  84.                 if(line != null && line.equals("exit")) {  
  85.                     break;  
  86.                 } else {  
  87.                     Message msg = new Message(nullnull"[" + userName + "]" + line);  
  88.                     channel.send(msg);  
  89.                 }  
  90.             }  
  91.             succeed = true;  
  92.         } finally {  
  93.             if(br != null) {  
  94.                 try {  
  95.                     br.close();  
  96.                 } catch (Exception e) {  
  97.                     if(succeed) {  
  98.                         throw e;  
  99.                     }  
  100.                 }  
  101.             }  
  102.         }  
  103.     }  
  104.       
  105.     public static void main(String args[]) throws Exception {  
  106.         new SimpleChat().start();  
  107.     }  
  108. }  

    在以上例子中,主线程会阻塞,直到从stdin中读取一行。如果这行是"exit",那么程序退出,否则向集群中发送一个消息。如果集群中某个实例强行退出,那么集群中的其它实例也会得到通知。Message构造函数的第一个参数如果是null,那么意味着消息将被发送到集群内所有的实例。

你可能感兴趣的:(jgroups)