JGroups 初探

本文介绍了如何使用JGroups框架实现一个简单的本地聊天程序,并展示了该程序如何在不同端口间进行集群发现。通过启动GossipRouter,使程序能够在局域网内的不同设备间建立连接,验证了JGroups在实现跨设备通信方面的便利性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近研究 JAVA 集群技术,看到 jgroups 这个框架,网上有些例子,非常简单。

可以参考其官方网址:http://www.jgroups.org/manual/index.html

按捺不住,自己还是动手写了一个试试。

代码如下:

import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.View;
import org.jgroups.stack.GossipRouter;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * JGroups 测试
 *
 * @author hjj2017
 * @since 2016/1/14
 *
 */
public class HelloJGroups extends ReceiverAdapter { // <-- 注意这里, HelloJGroups 即是消息的发送者又是消息的接收者
    /** 用户名称 */
    private String _userName = null;
    /** JChannel */
    private JChannel _channel = null;

    /**
     * 开始测试
     *
     * @throws Exception
     *
     */
    private void start() throws Exception {
        // 在这里生成用户名, User.00
        this._userName = "User." + (int)(Math.random() * 100);

        // 创建 JChannel
        this._channel = new JChannel();
        this._channel.setReceiver(this);
        this._channel.connect("ChatCluster");

        // 事件循环
        this.eventLoop();

        // 事件循环结束之后,
        // 关闭 JChannel
        this._channel.close();
    }

    /**
     * 事件循环, 从终端读取文字
     *
     */
    private void eventLoop() {
        // 创建读入流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            try {
                // 输出提示符
                System.out.print("~> ");
                System.out.flush();

                // 从终端读取文字
                String ln = br.readLine();

                if (ln.equalsIgnoreCase("quit") ||
                    ln.equalsIgnoreCase("exit")) {
                    // 遇到 quit / exit 时,
                    // 退出当前循环
                    break;
                }

                // 创建并发送消息,
                // 消息内容是 "${userName} : ${ln}"
                Message msg = new Message(null, null, this._userName + " : " + ln);
                this._channel.send(msg);
            } catch (Exception ex) {
                // 输出错误日志
                ex.printStackTrace();
            }
        }
    }

    @Override
    public void viewAccepted(View v) {
        System.out.println("viewAccepted : " + v);
    }

    @Override
    public void receive(Message msg) {
        System.out.println(msg.getObject());
    }

    /**
     * 应用程序主函数
     *
     * @param args
     * @throws Exception
     *
     */
    public static void main(String[] args) throws Exception {
        new HelloJGroups().start();
    }
}

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

-------------------------------------------------------------------
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 文件,文件内容大致如下:

<?xml version="1.0" encoding="utf-8" ?>
<config xmlns="urn:org:jgroups"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">

    <TCP />
    <!--// 注意 : 下面的 xxx.xxx.xxx.xxx 需要换成真实 IP //-->
    <TCPGOSSIP
        timeout="3000"
        initial_hosts="xxx.xxx.xxx.xxx[12001]" 
        num_initial_members="3"
    />
    <!--// 我试验过 TCPPING, 但是失败了 //-->

    <VERIFY_SUSPECT timeout="1500"  />
    <pbcast.NAKACK 
        use_mcast_xmit="false"
        retransmit_timeout="300,600,1200,2400,4800"
        discard_delivered_msgs="true"
    />
    <pbcast.STABLE 
        stability_delay="1000"
        desired_avg_gossip="50000"
        max_bytes="400000"
    />
    <pbcast.GMS 
        print_local_addr="true"
        join_timeout="5000"
        view_bundling="true"
    />

</config>
  • 第 3 步,修改 JChannel 创建代码,这是最后一步:
// 只能使用文件绝对路径, 
// 使用相对路径, JChannel 会产生歧义
final String xmlAbsPath = ClassLoader.getSystemResource(".").getPath() + "myConf.xml";
this._channel = new JChannel(xmlAbsPath);

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

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

转载于:https://my.oschina.net/hjj2017/blog/603439

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值