概述
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,或者在客户端中增加可靠性。
- 至少发一次(NATS Streaming)
提供更高的的QoS,但是会付出降低吞吐率和增加延迟的代价。
Request/Reply
publisher往主题中发布一个带预期响应的消息,subscriber执行请求调用,并返回最先的响应。 支持两种请求-响应消息通信模式:
- 点对点:最快、最先的响应。
- 一对多:可以限制Requestor收到的应答数量。
Queueing
subscriber注册的时候,需指定一个队列名。指定相同队列名的subscriber,形成一个队列组。当主题收到消息后,订阅了此主题的队列组,会自动选择一个成员来接收消息。尽管队列组有多个subscriber,但每条消息只能被组中的一个subscriber接收。
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