首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >集群开源软件赏:JGroups

集群开源软件赏:JGroups

作者头像
韩伟
发布2018-03-05 15:38:09
2.5K0
发布2018-03-05 15:38:09
举报
文章被收录于专栏:韩伟的专栏韩伟的专栏

目前我在腾讯主要负责一个服务器端软件的相关开源项目,所以接下来几天的开源内容是最近工作上积累的一些经验和想法,下图中的内容就是我目前主要的工作内容和一些小小的成果。

以下正文:

JGroups介绍

我们在开发集群系统的过程中,往往需要在多个进程间同步很多状态,比如每个服务器进程的负载状况、数据队列长度等等……。还有一些情况,我们需要把不同的进程分类,然后分发不同的通知消息,最常见的是发出一些运维命令,如回写数据、清理缓存……。在游戏服务集群中,需要群发消息的功能更是常见,比如全副广播、玩家在线列表维护……。因此我们往往需要实现“分组”“广播”的功能。在开源软件库中,有一款专门完成这类工作的产品,叫做JGroups。

这是一款Apache基金会下的Java语言开源库,官网地址是:http://jgroups.org/

集群服务中,各节点之间的通信能力至关重要。如果个个节点(进程)无法通信,集群将无法协同工作。——这正是JGroups的目标。在一般的情况下,我们可能会选择使用“消息队列”,比如JAVA就有JMS的消息队列规范,而Apache的开源软件ActiveMQ正是实现JMS规范的著名软件。但是,消息队列在使用的时候会显得太“重”,他需要额外启动的队列进程:存储队列消息,特定的进程间通信接口。对于希望能构建轻量级集群的方案里,部署一堆消息队列进程,然后配置管理他们,都是非常麻烦的。而jgroups则正好填补了这个空缺:它是一个库,使用API接口就好了,无须对协议编程;它让你的业务进程直接有通信的能力。

jgroups本身的通信能力,是基于UDP的,因此也支持使用UDP组播能力。这在轻量的服务集群中非常实用:往往一批服务器都连在同一个交换机上。这种情况下的UDP组播丢包率低,时延也低,而且能有效利用内网带宽。

jgroups自身的架构,和很多开源的通信库一样,是分层的。应用程序使用JChannel构建的使用界面API,以“频道”的模型来使用通信能力。底层则分为多个不同能力的实现层。

组播功能

我们先来看看如何用jgroups实现通信功能。jgroups是一个库,因此完全通过API编程就能让你的进程实现通信能力,无须安装部署任何其他软件。

首先,你需要建立一个频道,并连接进去。这个频道无须额外配置,只要调用代码就可以了。其次,构造一条需要发送的消息,这个消息包括内容、发送方地址、接收方地址。接收方地址标识在对应的频道中的具体接收目标,如果不填就是广播,频道中所有节点都会收到,消息的内容就是byte[],也就是任何的数据类型都可以。最后,注册一个接受消息的接口回调对象,让这个对象也连接到同样名字的频道就可以了。

//加入集群 
JChannelchannel = new JChannel();
channel.connect(“pushserver2”);
//发送消息,参数一是接收方地址,参数二是发送方地址;如果接收方地址是null,表示广播
Message msg= new Message(null, channel.getAddress(), “hello”.getBytes());
channel.send(msg);
//接收消息,Receiver类是实现了ReceiverAdapter接口的 
ReceiverAdapter receiver = new Receiver();
channel.setReceiver(receiver);
channel.connect(“pushserver2”);
//接收回调函数 
@Override
public void receive(Message msg)
{
         byte[]buf = msg.getBuffer();
}

在以上操作的过程中,每个节点(进程)对于“频道”的状态,是在不断变化的。下图表述了这种变化:

除了直接用JChannel来收发消息外,jgroups还提供了一种叫BuildingBlocks的使用方法。这个其实是对JChannel更高级的一种封装。主要分为Message Dispatcher和Rpc Dispatcher。

MessageDispatcher可以直接不显式建频道进行广播和单播,每次调用就完成一次简单的调用。这样就无须编码维护JChannel的状态。RpcDispatcher则更好用,他通过JAVA的反射功能,直接调用目标节点上的方法。他们的使用接口如下:

MessageDispatcher
public <T>RspList<T> castMessage(final Colllection<Address>dests, Message msg, RequestOptions options) //广播 
public <T>T sendMessage(Message msg, RequestOptions opts) //单播 
RpcDispatcher
public <T> RspList<T> callRemoteMethods(
                   Collection<Address>dests,
                   Stringmethod_name,
                   Object[]args,
                   Class[]types,
                   RequestOptionsoptions) throws Exception;

发现功能

在集群系统中,我们除了要给节点发消息,还需要随时了解集群中节点的状况。因此jgourps也提供了对应的接口,让我们了解这些情况。用法就是实现MembershipListener这个接口,其中的回调方法就会由jroups在发生事件时调用。

//状态回调接口 
public interfaceMembershipListener 
{
 voidviewAccepted(View new_view); //集群成员有变化 
 voidsuspect(Object suspected_mbr); //可能有节点挂了 
 voidblock();  //表示发送消息将被阻塞 
 voidunblock();  //表示发送消息将不再被阻塞 
}

状态传递

在集群系统里面,有时候我们不仅仅是通过消息来传递消息,还需要“同步”一些状态。也就是说不是说发一个内容给对方,而是让多个节点获得一致的数据,这个状态是在同一个“组”里面共享的。如果用广播API去做这个事情,自己还需要编写一堆代码。所以jgroups直接提供了一套易用的API来完成这个事。

首先,任何一个节点都可以对任何一个组,发起状态同步的请求。然后,在组中的“最老”的节点,就会有一个回调函数被调用,这个回调函数负责发送状态数据给请求者。状态数据可以是任何类型,是通过一个OutputStream来发送的。当然我们常常会使用JDK的ObjectOutputStream来直接发送一个状态对象。最后,这个状态请求者就会收到一个回调,数据由参数的InputStream传入。这套API的特点是,发送数据和接收数据者并不需要互相知道,而是通过一个组关联起来,这样就避免了复杂的地址管理工作。因为组中的成员可能随时退出和加入,要维持一个公共的数据变得很麻烦。

1. 发起状态请求:

public void getState(Addresstarget, long timeout) throws Exception;

2. 触发某一节点(最老)回调:

public void getState(OutputStreamoutput) throws Exception;

3. 触发请求者的回调:

public void setState(InputStreaminput) throws Exception;

协议

由于jgroups是一个组播的通信库,因此其协议栈包含了其内部支持的功能。这里列举一下:

  1. 消息传输:UDP/TCP/TUNNEL
  2. PING :发现协议,IP多播
  3. MERGE3:合并子集群回归一整个集群
  4. FD_SOC:故障检测
  5. VERIFY_SUSPECT:Double-checks故障节点
  6. BARRIER:状态传输
  7. UFC/MFC:单播、多播流量控制协议

可以看到,为了实现组播,其实底层是需要有很多网络维护工作的,特别是集群中节点故障状态的控制,由于jgroups帮我们做了,所以我们才可以这么简单的完成可靠性如此之高的组播功能

思考

jgrops的功能固然强大,但是让我更感兴趣的是其设计思想,这个产品体现出很多设计上的闪光点:

1. 如何简化集群管理接口。在很多方案中,集群管理库都是使用起来非常复杂的,但是jgroups设计了几个模型,大大简化了使用者需要理解的概念。

a) 使用IP组播或dir地址标识集群

b) 多个功能的集群可以合并到一个集群做管理,区分“组”单位即可

c) 自定义字符串节点组的名字

d) 通知集群变化的回调

e) 基于byte[]和对象的操作API

2. 对于集群环境的启示。我们在实际工作中,集群往往是按需搭建的,因此缺乏统一、有效的集群模型,其中有技术上实现难度的原因,也有思维上缺乏构建模型的原因,但是jgroups让我们发现,集群的管理功能,如状态同步、消息传递、底层通信都可以模块化设计的。

a) 可重用的集群状态管理和通信组件库

b) 隔离底层具体技术实现,而以Channel为单位管理

c) 丰富的非功能需求集成

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。如有不同意见,欢迎后台留言探讨。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 韩大 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JGroups介绍
  • 组播功能
  • 发现功能
  • 状态传递
  • 协议
  • 思考
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档