最近研究 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. }

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

  1. -------------------------------------------------------------------
  2. GMS: address=WINX-HOME-, cluster=ChatCluster, physical address=192.168.1.2:
  3. -------------------------------------------------------------------
  4. viewAccepted : [WINX-HOME-|] [WINX-HOME-]
  5. ~>
  6.  
  7. -------------------------------------------------------------------
  8. GMS: address=WINX-HOME-, cluster=ChatCluster, physical address=192.168.1.2:
  9. -------------------------------------------------------------------
  10. viewAccepted : [WINX-HOME-|] [WINX-HOME-, WINX-HOME-]
  11. ~>

可以看到,第二个启动的“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 创建代码,这是最后一步

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

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

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

JGroups 初探的更多相关文章

  1. 初探领域驱动设计(2)Repository在DDD中的应用

    概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...

  2. CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探

    CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...

  3. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  4. JavaScript学习(一) —— 环境搭建与JavaScript初探

    1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...

  5. .NET文件并发与RabbitMQ(初探RabbitMQ)

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...

  6. React Native初探

    前言 很久之前就想研究React Native了,但是一直没有落地的机会,我一直认为一个技术要有落地的场景才有研究的意义,刚好最近迎来了新的APP,在可控的范围内,我们可以在上面做任何想做的事情. P ...

  7. 【手把手教你全文检索】Apache Lucene初探

    PS: 苦学一周全文检索,由原来的搜索小白,到初次涉猎,感觉每门技术都博大精深,其中精髓亦是不可一日而语.那小博猪就简单介绍一下这一周的学习历程,仅供各位程序猿们参考,这其中不涉及任何私密话题,因此也 ...

  8. Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  9. NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例

    一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...

随机推荐

  1. Log4net 根据日志类别保存到不同的文件,并按照日期生成不同文件名称

    <configuration> <configSections> <!--日志记录--> <section name="log4net" ...

  2. 【IIS】 常见问题

    [IIS] 常见问题 1. IIS 安装 .Net FrameWork 4.0 开始->所有程序->附件->鼠标右键点击“命令提示符”->以管理员身份运行->%windi ...

  3. Oracle 学习笔记(四)

    ​oracle表查询 使用逻辑操作符号  查询工资高于 500 或者是岗位为 MANAGER 的雇员,同时还要满足他们的姓名首字母为大写 J SELECT * FROM emp WHERE (sal ...

  4. 「个人训练」Copying Books(UVa714)

    好久不更新主要是怠惰了....还要加强训练. 题意分析与思路 注意到这样一句话: our goal is to minimize the maximum number of pages assigne ...

  5. python第三天(list,元组,dictionary)

    1.list 列表 列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现. 列表的数据项不需要具有相同的类型 创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可.如下 ...

  6. [转]如何清空Chrome缓存和Cookie

    当您使用浏览器(例如 Chrome)时,浏览器会将网站中的一些信息保存在其缓存和 Cookie 中. 清除这些内容可以解决某些问题,例如网站上的加载或格式设置问题. 在 Chrome 中 在计算机上打 ...

  7. CentOS7中rpm,yum软件安装命令

    RPM包常用安装位置说明 /etc/                   配置文件安装目录 /usr/bin/               可执行的命令安装目录 /usr/lib/           ...

  8. vuex中获取的数据使用v-model绑定出问题

    get selectedProp() { return this.$store.state.selectedProp; } 获取的数据selectedProp直接绑定在表单元素上会有错,因为不能直接对 ...

  9. CSS的基本使用

    CSS的出现就是为了将HTML的内容与样式分离 CSS的书写方式 selector{ key:value } h1{ color: blue; } <!DOCTYPE html> < ...

  10. ASP.NET页面之间传值Cookie(3)

    这个也是大家常使用的方法,Cookie用于在用户浏览器上存储小块的信息,保存用户的相关信息,比如用户访问某网站时用户的ID,用户的偏好等, 用户下次访问就可以通过检索获得以前的信息.所以Cookie也 ...