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 及分布式缓存,还是相当容易的。

  • 相关阅读:
    Docker容器启动时初始化Mysql数据库
    使用Buildpacks高效构建Docker镜像
    Mybatis 强大的结果集映射器resultMap
    Java 集合排序策略接口 Comparator
    Spring MVC 函数式编程进阶
    换一种方式编写 Spring MVC 接口
    【asp.net core 系列】6 实战之 一个项目的完整结构
    【asp.net core 系列】5 布局页和静态资源
    【asp.net core 系列】4. 更高更强的路由
    【Java Spring Cloud 实战之路】- 使用Nacos和网关中心的创建
  • 原文地址:https://www.cnblogs.com/afritxia2008/p/5134485.html
Copyright © 2011-2022 走看看