Introduction to NATS

本文主要了NATS的工作原理,以及它在CloudFoundry是如何与其它组件协同工作的。

Introduction to NATS

在CloudFoundry系统中,包含许多内部组件,如CloudController、DEA、Router等等,如果某个组件(如DEA)需要去订阅其它组件的消息,那么DEA需要找到其它每一个组件并在其上注册事件,如果需要在每一个组件上注册多个事件,那么每个事件都需要执行一次上述过程(找到该组件并注册事件),这将增大系统的复杂度,并且使系统更加耦合,从而降低了系统的可扩展性。而NATS则解决了CloudFoundry的内部组件的通讯问题。

NATS是一个轻量级的分布式的消息订阅发布系统,CloudFounery使用NATS作为内部组件的通讯系统,从而进行基于主题的消息订阅和发布。NATS是基于EventMachine,由Ruby实现的,它由NATS客户端和服务端组成。客户端负责向服务端发送指令(订阅主题,发布主题等等),而服务端则接收并处理来自客户端的指令,并做出响应。目前,NATS客户端同时也支持node.js、Go、Java以及Java-Spring的实现。

NATS Application Protocol

NATS是一个典型的网络应用程序,也就是说NATS客户端和服务器端是通过计算机网络通信的,NATS在此基础之上定义了属于自己的一套应用层协议。如下所示:

NATS生命周期

NATS示例代码

以下面的NATS客户端和服务端代码为例,简单介绍一下NATS的整个生命周期。

NATS Server:

NATS Sample Server

图1 NATS Sample Server

NATS Client:

NATS Sample Client

图2 NATS Sample Client

NATS生命周期时序图

下面是NATS的完整的生命周期时序图。

NATS Life Circle

图3 NATS 生命周期

  1. 首先NATS Client需要建立与Server端的TCP连接,之后NATS Server会发送一个“INFO”消息至客户端,其中会包含Server端的详细信息,包括NATS Server的ID,host, port, version,以及是否需要用户验证,是否支持SSL等等;

  2. 之后NATS Client会发送一个“CONNECT”消息至Server端,其中包含客户端的详细信息,Server端会根据配置来验证该客户端; 如果通过,会返回一个“+OK”消息;

  3. 此时,TCP连接已经成功建立,Client会发送一个“PING”消息给Server,而Server会直接返回“PONG”消息给Client,之后Client可以订阅或是分发事件;

  4. NATS Client订阅一个主题为“A.B.C”的消息,它的Subject Identifier是2(每次订阅时该ID会自增+1);

  5. 之后NATS Client会发布一个主题为“A.B.C”的消息,消息长度为8,内容为“I‘m Yuan”;

  6. 最后,Server端会根据主题匹配算法,找到相应的订阅方,然后发送一个“MSG”消息给订阅方,并且带上主题“A.B.C”和主题ID“2”;

  7. 此时,在NATS Client端,就可以根据主题ID找到相应的订阅者,执行相应的callback。

NATS主题匹配

当一个NATS Client向NATS Server订阅一个消息后,Server会保留该订阅者的信息,包括当前主题,主题ID等等(具体参见图4),之后会根据主题匹配算法找到相应订阅者,并发布消息。

NATS主题特性

例子如下所示:

插入主题 匹配主题 不匹配主题
A.B.C A.B.C A.D.C
A.*.C A.B.C/A.D.C/A.*.C A.B.D
A.B.> A.B.C/A.B.C.D.E.F.G A.C.D.E.F.G

NATS主题数据结构

在NATS服务器端内部,是由sublist.rb负责主题匹配工作的,它是由SublistLevel和SublistNode两个结构体组成的树形结构,如图4所示。SublistLevel主要维护的是token(包括二个特殊的通配符)至SublistNode节点的映射,而SublistNode主要保存的是订阅者信息,以及与下级SublistLevel的关系。Subscriber保存的是订阅方的信息,包含当前的Connection,主题,主题ID等等。

NATS Subject Structure

图4 Sublist、Subscriber 结构

NATS主题匹配算法

当NATS Server收到基于主题“A.B”的PUB消息后,它会把“A.B”主题拆分成二个token,然后将每个token中的内容从Sublist的Root Level开始从上至下开始进行匹配。如果每个Token都能匹配到节点,那么最后一个Token对应的SublistNode就是这个主题的订阅者。

NATS Subject Matching Algorithms

图5 Sublist Workflow

NATS与其它CloudFoundry组件

NATS与Router

Router组件主要是对所有的请求进行路由,包括管理请求和App应用请求,其它组件如果想让Router路由请求由需要先向Router注册。过程如下:

  1. Router启动时,会订阅router.registerrouter.unreigster这两个channel,等待其它组件向这二个channel发送消息;
  2. 同时,Router会向router.startchannel发送消息,其它需要向Router注册的组件(如DEA)在启动时都需要订阅router.start这个channel,一旦接收到该消息,都需要将需要注册的信息(DEA会包括host, port, uris, tags, app等等)向router.register channel发送;
  3. Router接收到router.register消息后,会立即更新路由消息;同时,如果Router收到router.unregister消息,那么它会立即删除该路由信息;

另外,Router还订阅了router.greet这个channel,主要用于如果某个组件比NATS启动晚时,从而没有收到router.start消息时,也可以让该组件向Router注册路由信息,DEA也采用了这种方式来保证路由注册。

Router同时每隔一段时间(默认是0,所以不会发送)也会通过router.active_apps这个channel向其它组件发送当前active的app id信息。

NATS与HealthManager

HealthManager组件主要是从DEA拿到app的各类运行信息,然后进行统计、分析和报警,如果某个instance出现异常,HM可以通过NATS通知CC启用或停止该instance。

HM订阅的DEA状态相关channel:

HM订阅的app状态查询相关的channel:

HM不仅统计应用的运行信息,它也会分析应用的状态。与此相关的channel:

NATS与DEA、CloudController

DEA是一个安装在DEA VM node上的ruby的agent,由它来管理App的整个生命周期,包括stage, start, stop等等。 具体的流程可以参见How Application Are Staged。 与DEA相关的最重要的二件事是Staging app和Run app,都是由CloudFoundry通过NATS来触发的。

NATS与DEA、CloudController主要交互工作流程如下:

总结

对于CloudFoundry来说,NATS的作用是必不可少的。NATS让CF系统中的各组件各司其职,各个组件之间可以不需要知道互相的存在,只是通过简单的消息订阅发布来完成异步消息的通信和协同工作,彻底让系统解耦。同时NATS也大大的提高了系统的可维护性和可扩展性,这让我们增加新的组件也更加简单,更加高效。

Related Posts

Xin(Khalil) Zhang 08 December 2014
blog comments powered by Disqus