集群开源软件赏:JGroups

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

以下正文:

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) 丰富的非功能需求集成

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

原文发布于微信公众号 - 韩大(handa1740168)

原文发表时间:2016-01-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏无题

读曾宪杰《大型网站系统与Java中间件实践》

十年,一个时代过去 1.分布式系统相对集中式而言,是指多台计算机互相通过消息通信进行协作而对外提供服务;可解决大型机的伸缩性和单点等问题; 2.网络i/o有b...

2925
来自专栏Java学习网

Java开发人员必备工具之 10 个大数据工具和框架

先来看看大数据的概念。根据维基百科,大数据是庞大或复杂的数据集的广义术语,因此传统的数据处理程序不足以支持如此庞大的体量。

873
来自专栏ImportSource

消息队列可以有的样子

铺垫 无论是什么类型的消息队列,恐怕都离不开三个东东:读取端 、消息存储平台、写入端,无论你给这三者起了什么样子的名字。也就是写入、存储、读取。 写入端通常被叫...

3756
来自专栏JAVA烂猪皮

kafka 数据可靠性深度解读

Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用。目前越来...

841
来自专栏携程技术中心

携程2015 Open House获奖项目:火车票订单中心重构

给绿皮车换上高铁发动机 火车票订单中心重构 web订单系统,对我们来说,都不是一个陌生的东西。然而,高并发从技术的角度来说,这对于Web系统是一个巨大的考验。当...

1968
来自专栏美团技术团队

【技术博客】Cache应用中的服务过载案例研究

简单地说,过载是外部请求对系统的访问量突然激增,造成请求堆积,服务不可用,最终导致系统崩溃。本文主要分析引入Cache可能造成的服务过载,并讨论相关的预防、恢复...

2985
来自专栏分布式系统和大数据处理

Kafka分布式消息系统(基本概念) - Part.1

本来打算给这篇文章起名叫“搭建Kafka消息队列集群”,然而,和RabbitMQ不同,Kafka并没有实现消息队列的协议(例如AMQP,Advanced Mes...

812
来自专栏Java技术栈

网站性能测试指标(QPS,TPS,吞吐量,响应时间)详解

常用的网站性能测试指标有:吞吐量、并发数、响应时间、性能计数器等。 并发数 并发数是指系统同时能处理的请求数量,这个也是反应了系统的负载能力。 响应时间 响应时...

5128
来自专栏Java进阶架构师

「架构技术专题」构建网站高可用架构(详细分析篇)(6)

可用性指标时网站架构设计的重要指标,对外是服务承诺,对内是考核指标,具体到每个工程师,更多的是使用故障分。

563
来自专栏架构师之路

究竟啥才是互联网架构“高可用”

一、什么是高可用 高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。 ...

4126

扫码关注云+社区