NATS消息系统

开源、安全、轻量级、可伸缩、高性能的分布式消息通信系统

Posted by Robin on January 15, 2017

概述

NATS是一个开源、安全、轻量级、可伸缩、高性能的分布式消息通信系统。NATS服务器是Golang语言开发,客户端由官方和社区提供了10多种语言的客户端。

简介

NATS设计目标:

  • 高性能(fast)
  • 高可用(dial tone)
  • 轻量级(small footprint)
  • 支持多种QoS(at-least-once/at-most-once)
  • 支持多种消息通信模型和用例场景(flexible)

优势和劣势

优势

  • 纯发布/订阅
  • 集群式服务器
  • 自动修剪订阅者
  • 基于文本的协议

劣势(不提供)

  • 持久化
  • 事务处理

NATS Messaging

NATS通讯原理:Publisher编码并发送消息;一个或多个Subscriber接收、解码并处理消息。

Subscriber处理消息模式

  • Asynchronous

通过注册handler来接收和处理消息。当收到消息时,会自动触发handler。这种消息处理模式不会被阻塞,可以同时执行其他任务。

  • Synchronous

通过显示调用方法来接收和处理消息。这种消息处理模式会被阻塞,会暂停任务直到收到新的消息。Synchronous模式主要用于服务器端,等待并处理请求的信息,并发送响应给客户端。

消息模式

支持3种消息模式:

Publish/Subscribe

Publish/Subscribe是一对多的消息模型。Publisher往一个主题上发送消息,任何订阅了此主题的Subscriber都可以接收到该主题的消息。

服务质量指标:

  • 至多发一次

NATS系统是一种“发送后不管”的消息通信系统。往某主题上发送时,如果没有subscriber,或者所有subscriber不在线,则该消息不会给处理。如果需要更高的QoS,可以使用NATS Streaming,或者在客户端中增加可靠性。

提供更高的的QoS,但是会付出降低吞吐率和增加延迟的代价。

drawing

Request/Reply

publisher往主题中发布一个带预期响应的消息,subscriber执行请求调用,并返回最先的响应。 支持两种请求-响应消息通信模式:

  • 点对点:最快、最先的响应。
  • 一对多:可以限制Requestor收到的应答数量。

drawing

Queueing

subscriber注册的时候,需指定一个队列名。指定相同队列名的subscriber,形成一个队列组。当主题收到消息后,订阅了此主题的队列组,会自动选择一个成员来接收消息。尽管队列组有多个subscriber,但每条消息只能被组中的一个subscriber接收。

drawing

NATS Protocol

NATS连接协议是一个简单的、基于文本的发布/订阅风格的协议。与传统的二进制消息格式的消息通信系统不同,基于文本的NATS协议,使得客户端实现很简单,可以方便地选择多种编程语言或脚本语言来实现。

协议约定

主题

大小写敏感,必须是不能包含空格的非空字符串,可以包含标志分隔符”.”。

通配符

订阅主题中可以使用通配符,但是通配符必须被标识分隔。支持两种通配符:

  • 星号*:匹配任意层级中的任意标记,如A.*.
  • 大于号>:匹配所有当前层级之后的标记,如A.>

新行

CR+LF(即\r\n,0X0D0A)作为协议消息的终止。新行还用于标记PUB或MSG协议中消息的实际有效负载的开始。

协议操作

操作名是大小写不敏感的。详细的操作,参考NATS Protocol

Protocol Messages

Client操作之后,Server都会给出相应的信息。

  • +OK:Server响应正确。
  • -Err:协议错误,将导致Client断开连接。

Demo

实验环境

NATS protocol是基于文本的,Client通过普通的TCP/IP套接字与服务器通信,因此NATS使用起来是非常方便和容易。

如果想体验和实现NATS,只需要搭建NATS服务器,通过Telnet连接,就可以尝试NATS的协议操作进行实验。获得NATS服务器的两种途径:

  • 官方测试服务器:demo.nats.io
  • 基于Docker镜像创建

Docker Hub有很多NATS的镜像,包括一些官方提供的。通过docker search命令查找:

$ docker search nats
INDEX       NAME                                             DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/nats                                   NATS is an open-source, high-performance, ...   96        [OK]       
docker.io   docker.io/nats-streaming                         NATS Streaming is an open-source, high-per...   12        [OK]     

一般从Docker Hub上选择镜像的原则:STARS越多越好;OFFICIAL更加靠谱。

在自己一台Docker Host上,通过如下命令创建NATS服务器:

docker run -id -p 4222:4222 -p 8222:8222 -p 6222:6222 docker.io/nats:0.9.4

直接访问这台机器的4222端口,就可以连接到NATS服务器上。

实验演示

下面的所有演示,都是通过Telnet连接到官方测试服务器demo.nats.io进行的。

  • 连接服务器
$ telnet demo.nats.io 4222
Trying 107.170.221.32...
Connected to demo.nats.io.
Escape character is '^]'.
INFO {"server_id":"O4PDgd2slz5h90ZZbGoCCA","version":"0.9.4","go":"go1.6.3","host":"0.0.0.0","port":4222,"auth_required":false,"ssl_required":false,"tls_required":false,"tls_verify":false,"max_payload":1048576} 
  • Publis/Subscribe模式

开启两个Terminal T1和T2,分别为Subscriber和Publisher。同时将它们连接到服务器上后,先T1执行SUB订阅主题foo,然后T2执行PUB往主题foo中发送消息。

T1:

SUB foo 1
+OK
MSG foo 1 5
hello
MSG foo 1 4
nats

T2:

PUB foo 5
hello
+OK
PUB foo 4
nats
+OK
  • Queueing模式

开启三个Terminal T1,T2,T3和T4,T1,T2和T3都为Subscriber,T4为Publisher。同时将它们连接到服务器上后,先T1,T2和T3执行SUB订阅主题foo,然后T4执行PUB往主题foo中发送消息。

T1: 在组g1中,与T2只有一个能收到消息。

sub foo g1 1
+OK
MSG foo 1 5
nats1

T2: 在组g1中,与T1只有一个能收到消息。

sub foo g1 2
+OK
MSG foo 2 5
hello

T3: 不在组g1中,能收到所有消息。

sub foo 3
+OK
MSG foo 3 5
hello
MSG foo 3 5
nats1

T4:

pub foo 5
hello
+OK
pub foo 5
nats1
+OK
  • 通配符

开启三个Terminal T1,T2,T3和T4,T1,T2和T3都为Subscriber,T4为Publisher。同时将它们连接到服务器上后,先T1,T2和T3执行SUB订阅不同主题,然后T4执行PUB往不同主题中发送消息。

T1: 只能订阅foo的消息。

sub foo 1
+OK
MSG foo 1 4
msg1

T2: 只能订阅foo开头两个层级的主题,但是不能订阅foo。

sub foo.* 2
+OK
MSG foo.bar 2 4
msg2

T3: 只能订阅foo开头任意层级的主题,但是不能订阅foo。

sub foo.> 3
+OK
MSG foo.bar 3 4
msg2
MSG foo.bar.zoe 3 4
msg3

T4:

pub foo 4
msg1
+OK
pub foo.bar 4
msg2
+OK
pub foo.bar.zoe 4
msg3
+OK