想要向服务器发送请求并得到响应?直接使用 HTTP 吧!很是简单。可是当须要经过持久的双向链接来通讯时,如 WebSockets,固然你也有其它的选择。
这篇文章会简单扼要的解释 MQTT,XMPP,STOMP,AMQP,WAMP 和其它替代品。这里常被引用的 XKCD 漫画[1]之一:编程
确实如此,但这里我将该术语(Realtime Protocol)看成一堆协议的代称,这类协议都是设计用于分发消息,同步数据和经过持久双向的链接来进行请求/响应。浏览器
咱们先来根据它们各自的目的进行分类:缓存
底层协议(例如 TCP)是被设计用来将一个消息从一个发送者(sender)传递给一个接收者(receiver)。他们并不关系消息自己应该如何构建,也不关系消息的请求、获取、存储以及如何保证安全可靠。
像 WebSockets 这样在 TCP 之上的协议,添加了一些额外的功能,例如使用头部(header)传输元数据,经过多个数据包分割较大的消息,简单的身份验证,以及路由/重定向相关信息。本质上它们仍然是点对点交换数据的方式。
当涉及到构建更大,更复杂的系统时,你须要一个更高层次的通讯范式:安全
发布-订阅模式是在大规模系统中被普遍使用的通讯方式,用于多对多无状态消息传递。“订阅者”(Subscribers)能够订阅“消息主题”(topics,channels,events,namespaces), “发布者”(Publishers)能够将消息发布到“消息主题”,经过路由,全部的订阅者都将收到。
这种范式是很是灵活,高效和可扩展。它将发送者与接收者隔离开,容许订阅者自由得订阅主题或取消订阅。这和咱们平常订阅报纸是同样的。
有许多支持发布-订阅的协议:MQTT,STOMP,WAMP 等等。那么咱们应该如何选择呢?服务器
MQTT(Message Queue Telemerty Transport)[2]是一种二进制协议,主要用于服务器和那些低功耗的物联网设备(IoT)之间的通讯。
它位于 TCP 协议的上层,除了提供发布-订阅这一基本功能外,也提供一些其它特性:不一样的消息投递保障(delivery guarantee),“至少一次”和“最多一次”。经过存储最后一个被确认接受的消息来实现重连后的消息恢复。网络
它很是轻量级,而且从设计和实现层面都适合用于不稳定的网络环境中。架构
物联网(IoT)场景中更适合,支持几乎全部语言进行开发,而且浏览器也可经过 WebSocket 来发送和接收 MQTT 消息。
编程语言
同时,对于MQTT Broker,也有不少选择,如 Mosquitto[3] 或 VerneMQ[4] 以及基于云的 MQTT 平台,如 HiveMQ[5] 或 CloudMQTT[6]。学习
面向流文本的消息传输协议(STOMP,Streaming Text Oriented Messaging Protocol)[7],是 WebSocket 通讯标准。在一般的发布-订阅语义之上,它经过 begin/publish/commit 序列以及 acknowledgement 机制来提供消息可靠投递。
ui
因为协议简单且易于实现,几乎全部的编程语言都有 STOMP 的客户端实现。可是在消息大小和处理速度方面并没有优点。
当与 Apache Apollo[8] 这样的多协议代理(multi-protocol broker)中间件结合使用时,能够作许多有趣的集成。好比在浏览器的图表中不断更新 IoT 设备的数据。
到目前为止,咱们已经讲了两个协议:一个二进制、另外一个基于文本。让咱们快速比较一下差别:
经过控制线缆中光或电的打开或关闭(逻辑开关),或控制 WiFi 信号的波峰或波谷来实现计算机之间的信息交换。从原理上来讲,这是基于二进制的形式。所以,从这个层面来讲全部协议都是二进制协议。
信息一旦发送,接收方有两个选择:它能够将 0/1 流分组成字节序列,进而获取(解析)信息;或者能够执行额外的步骤,将其转换为文本,而后再解析此文本。
前一种方法称为(基于)二进制的。它节省了一些昂贵的操做,同时是传输任何非文本信息的标准形式。例如,图像,音频,视频或文件。固然它也可用于发送文本信息。例如,经过向每一个消息增长几个字节来表达元信息,好比描述该消息的长度或类型,这样就只需将实际的消息数据转换为文本。
然而,因为在许多发布-订阅式的架构中,信息交换是基于文本的,因此许多协议选择简单地将整个信息转化为文本,从而下降复杂性并提升了可读性,固然带来的代价就是须要再消息接受后执行额外的计算任务。
Web 应用消息协议(WAMP,Web Application Messaging Protocol)[9],它尝试开发一种开放的、基于文本的协议标准,而且结合了基于发布-订阅的请求/响应编程模型,同时具有强大的路由和消息投递策略。目前它被普遍用于集成 crossbar.io[10] 路由器和 autobahn 的高速缓存客户端[11]。
那些实时通讯平台即服务(Realtime platform-as-a-service)的产品,例如 Pusher 或 PubNub,一般使用它们本身的专有协议。Pusher 已经公开了它们研发的基于 JSON 协议的详细规范[12],而且鼓励第三方或社区帮助构建不一样语言的客户端。Pubnub 虽然更封闭一些,但它们目前支持一系列其它开放协议进行交互,如 MQTT。
有些场景下,简单的发布-订阅模式还不够。这就是队列存在的场合:它支持多种不一样的消息和存储的模式。
经过获取/确认策略,消费者接收到队列的一些消息,确认他们的“消费”,处理它们,而后取下一批消息。这是一个强大同时经常使用的方式。
想象一下,你正在构建一个相似 Instagram 的产品,它容许用户上传图片并添加各类滤镜。应用滤镜的过程是一个计算密集型的操做。所以,不能在上传时直接进行操做,因此接收图像的服务器只是记录下在文件系统中的位置,接着将“什么图像须要使用什么样的滤镜”这个任务添加到任务队列中。
另外一台专门用于处理滤镜的机器能够从任务队列中获取这个任务,读取原始图像文件,应用滤镜,并确认这个任务已经消费(完成)。以后为了水平扩展图像处理的能力,只须要添加更多的消费者(处理滤镜的机器)来处理任务队列便可。
这种模式很是易于扩展,能够添加复杂的路由策略,任务分配策略等。
高级消息队列协议(AMQP,Advanced Message Queuing Protocol)[13]是各类消息队列协议中的佼佼者。RabbitMQ[14] 和 HornetQ[15] 都是实现该协议的流行中间件。
当简单的发布-订阅模型不能知足使用要求。AMQP 十分可靠且功能强大。固然它及它的实现并非足够轻量级。若是你须要一个更轻量级的选择,那接下来的内容可能会更好:
ZeroMQ[16] 既是一个协议,也是一套协议实现的组件。提供比 AMQP 更高速同时去中心化的替代方案。
当你须要海量吞吐以及无单点故障风险的消息队列支撑你的复杂工做流,那么 ZeroMQ 是个不错的选择,固然,你须要对陡峭的学习曲线作好准备。
Java 消息服务(JMS,Java Messaging Service)[17],是协议同时也是 Java 消息服务规范的标准实现,同时也是 Java 企业版(JEE)规范的一部分。
当你使用 Java 栈,同时也为 Java Enterprise Platform 付费了,那 JMS 是最佳选择。若是没有,那就优先考虑上述那些方案。
有时咱们只须要发送单个请求,并等待收到一个响应,这彻底可使用HTTP请求完成 / 。 可是既然你已经创建了一个与服务器的持久链接 ,那为何不利用它呢?
这种经过持久链接进行的请求/响应模式的通讯过程,一般被称为远程过程调用(RPC,Remote Procedure Calls)或远程方法调用(RMI,Remote Method Invocation)。AMQP 或 ZeroMQ 能够经过响应队列(response-queue)来实现这种模式,JMS 能够直接支持 Java RMI。
DataSync 是实现实时通讯的最新可选方案。
DataSync 将数据存储中的数据同步给客户端。客户端对数据的变动都将同步给全部的订阅者。DataSync 隐藏了实时通讯类应用中维护数据状态的细节,下降了复杂性,并极大加快了开发速度,但它目前仍然是一种没有开放的协议标准。
目前 DataSync 已能够在几个 PaaS 平台上使用,如 deepstreamHub[18],Firebase[19] 或 Realm[20]。