zoukankan      html  css  js  c++  java
  • JGroups 初探

    最近研究 JAVA 集群技术,看到 jgroups 这个框架,网上有些例子,非常简单。
    可以参考其官方网址:http://www.jgroups.org/manual/index.html
    按捺不住,自己还是动手写了一个试试。代码如下:

      1 import org.jgroups.JChannel;
      2 import org.jgroups.Message;
      3 import org.jgroups.ReceiverAdapter;
      4 import org.jgroups.View;
      5 import org.jgroups.stack.GossipRouter;
      6 
      7 import java.io.BufferedReader;
      8 import java.io.InputStreamReader;
      9 
     10 /**
     11  * JGroups 测试
     12  *
     13  * @author hjj2017
     14  * @since 2016/1/14
     15  *
     16  */
     17 public class HelloJGroups extends ReceiverAdapter { // <-- 注意这里, HelloJGroups 即是消息的发送者又是消息的接收者
     18     /** 用户名称 */
     19     private String _userName = null;
     20     /** JChannel */
     21     private JChannel _channel = null;
     22 
     23     /**
     24      * 开始测试
     25      *
     26      * @throws Exception
     27      *
     28      */
     29     private void start() throws Exception {
     30         // 在这里生成用户名, User.00
     31         this._userName = "User." + (int)(Math.random() * 100);
     32 
     33         // 创建 JChannel
     34         this._channel = new JChannel();
     35         this._channel.setReceiver(this);
     36         this._channel.connect("ChatCluster");
     37 
     38         // 事件循环
     39         this.eventLoop();
     40 
     41         // 事件循环结束之后,
     42         // 关闭 JChannel
     43         this._channel.close();
     44     }
     45 
     46     /**
     47      * 事件循环, 从终端读取文字
     48      *
     49      */
     50     private void eventLoop() {
     51         // 创建读入流
     52         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     53 
     54         while (true) {
     55             try {
     56                 // 输出提示符
     57                 System.out.print("~> ");
     58                 System.out.flush();
     59 
     60                 // 从终端读取文字
     61                 String ln = br.readLine();
     62 
     63                 if (ln.equalsIgnoreCase("quit") ||
     64                     ln.equalsIgnoreCase("exit")) {
     65                     // 遇到 quit / exit 时,
     66                     // 退出当前循环
     67                     break;
     68                 }
     69 
     70                 // 创建并发送消息,
     71                 // 消息内容是 "${userName} : ${ln}"
     72                 Message msg = new Message(null, null, this._userName + " : " + ln);
     73                 this._channel.send(msg);
     74             } catch (Exception ex) {
     75                 // 输出错误日志
     76                 ex.printStackTrace();
     77             }
     78         }
     79     }
     80 
     81     @Override
     82     public void viewAccepted(View v) {
     83         System.out.println("viewAccepted : " + v);
     84     }
     85 
     86     @Override
     87     public void receive(Message msg) {
     88         System.out.println(msg.getObject());
     89     }
     90 
     91     /**
     92      * 应用程序主函数
     93      *
     94      * @param args
     95      * @throws Exception
     96      *
     97      */
     98     public static void main(String[] args) throws Exception {
     99         new HelloJGroups().start();
    100     }
    101 }

    这事一个简单的聊天程序,可以启动两次来观察结果。

    -------------------------------------------------------------------
    GMS: address=WINX-HOME-50829, cluster=ChatCluster, physical address=192.168.1.2:52477
    -------------------------------------------------------------------
    viewAccepted : [WINX-HOME-50829|0] [WINX-HOME-50829]
    ~> 
    
    -------------------------------------------------------------------
    GMS: address=WINX-HOME-1927, cluster=ChatCluster, physical address=192.168.1.2:59569
    -------------------------------------------------------------------
    viewAccepted : [WINX-HOME-50829|1] [WINX-HOME-50829, WINX-HOME-1927]
    ~> 


    可以看到,第二个启动的“WINX-HOME-1927”发现了第一个启动的“WINX-HOME-50829”。

    注意我是在本地测试的,这个程序启动时会临时绑定一个端口。

    启动两次,绑定两个不同的端口,会话过程是在同一台机器上的两个不同端口之间进行的。

    程序启动之后,这两个程序会互相发现对方,这是这个框架一个比较方便的地方。

    如果是在同一局域网里的两台不同的机器上会是什么结果呢?

    我在家里的两台 PC 机上测试过,两台 PC 的 IP 地址不相同(192.168.1.2 和 192.168.1.6),

    启动后仍然可以发现对方!

    当然,这里面有个前提,两台机器连接着同一台路由器。

    在真实的服务器环境中,所有的服务器都连接同一台路由器是不可能的!

    为此,我们可以启动 GossipRouter,令所有的 JGroups 程序都连接到这个 GossipRouter 上。

    我们大概需要做以下 3 步:

    1. 启动 GossipRouter,绑定了 12001 端口:

        java -Djava.net.preferIPv4Stack=true -cp .:commons-logging-1.1.3.jar:log4j-1.2.17.jar:jgroups-2.9.0.GA.jar org.jgroups.stack.GossipRouter -port 12001

    2. 创建 myConf.xml 文件,文件内容大致如下:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <config xmlns="urn:org:jgroups"
     3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4         xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">
     5 
     6     <TCP />
     7     <!--// 我试验过 TCPPING,但是失败了 //-->
     8     <TCPGOSSIP
     9         timeout="3000"
    10         initial_hosts="xxx.xxx.xxx.xxx[12001]" <-- 注意这里的 xxx.xxx.xxx.xxx 需要换成真实 IP
    11         num_initial_members="3"
    12     />
    13     <VERIFY_SUSPECT timeout="1500"  />
    14     <pbcast.NAKACK 
    15         use_mcast_xmit="false"
    16         retransmit_timeout="300,600,1200,2400,4800"
    17         discard_delivered_msgs="true"
    18     />
    19     <pbcast.STABLE 
    20         stability_delay="1000"
    21         desired_avg_gossip="50000"
    22         max_bytes="400000"
    23     />
    24     <pbcast.GMS 
    25         print_local_addr="true"
    26         join_timeout="5000"
    27         view_bundling="true"
    28     />
    29 
    30 </config>


    3. 修改 JChannel 创建代码,这是最后一步

    // 只能使用文件绝对路径, 
    // 使用相对路径, JChannel 会产生歧义
    final String xmlAbsPath = ClassLoader.getSystemResource(".").getPath() + "myConf.xml";
    this._channel = new JChannel(xmlAbsPath);

     
    关于 JGroups,目前我没有进行“大消息包”和“大集群量”的测试,还无法确定其性能表现。

    如果性能方面表现良好,JGroups 放在游戏项目中,实现跨服聊天、跨服 PK 及分布式缓存,还是相当容易的。

  • 相关阅读:
    CSS中的小知识
    网络基础 中的osi七层 协议
    pickle的使用
    max()的key的运用
    read,readline,readlines的区别
    print()控制台输出带颜色的方法
    写项目时bin目录下的start中的细节(路径问题的解决)
    使用hashlib密文存储实例
    固态硬盘使用f2fs作为根分区安装linux
    工厂方法(Factory Method)
  • 原文地址:https://www.cnblogs.com/afritxia2008/p/5134485.html
Copyright © 2011-2022 走看看