分布式系统中常用通讯模型主要是“请求-应答”模型和“发布-订阅”模型。前者常见如RPC通讯,常用HTTP REST或Thrift等协议;后者多指消息队列MQ通讯。
RPC大多属于请求-应答模式,也包括越来越多响应式范式,对于需要点对点交互、强事务保证和延迟敏感的服务/应用之间的通信,RPC是优于消息队列的。那么消息队列(下文也简称MQ,即Message Queue)可以看做是一种异步RPC,把一次RPC变为两次或多次,进行内容转存,再在合适的时机投递出去。消息队列中间件往往是一个分布式系统,内部组件间的通信仍然会用到RPC。
常见消息队列协议
底层协议(例如 TCP)是被设计用来将一个消息从一个发送者(sender)传递给一个接收者(receiver)。他们并不关系消息本身应该如何构建,也不关系消息的请求、获取、存储以及如何保证安全可靠。像 WebSockets 这样在 TCP 之上的协议,添加了一些额外的功能,例如使用头部(header)传输元数据,通过多个数据包分割较大的消息,简单的身份验证,以及路由/重定向相关信息。
消息队列场景中producer、consumer和broker通信的协议,包括AMQP、STOMP、MQTT、HTTP、OpenWire(ActiveMQ)、XMPP、自定义等等。以下对比较常用的几个说明:
1、STOMP: 面向流文本的消息传输协议(STOMP,Streaming Text Oriented Messaging Protocol),是 WebSocket 通信标准。在通常的发布-订阅语义之上,它通过 begin/publish/commit 序列以及 acknowledgement 机制来提供消息可靠投递。
特点:协议简单且易于实现,几乎所有的编程语言都有 STOMP 的客户端实现。但是在消息大小和处理速度方面并无优势。由于在许多发布-订阅式的架构中,信息交换是基于文本的,所以许多协议选择简单地将整个信息转化为文本,从而降低复杂性并提高了可读性,当然带来的代价就是需要再消息接受后执行额外的计算任务。
应用场景:信息交换基于文本,要求简单的场景。
典型实现:ActiveMQ以及它的下一代实现Apache Apollo。
2、AMQP:比较全面和复杂的一个协议,包括协议本身以及模型(broker、exchange、routing key等概念)。
特点:AMQP 十分可靠且功能强大。当然它及它的实现并不是足够轻量级。
应用场景:当简单的发布-订阅模型不能满足使用要求。
典型实现:RabbitMQ是AMQP消息队列最有名的开源实现。RabbitMQ同时还可以通过插件支持STOMP、MQTT等协议接入。Kafka、RocketMQ均使用自定义的协议。
3、MQTT:MQTT(Message Queue Telemerty Transport)是一种二进制协议,主要用于服务器和那些低功耗的物联网设备(IoT)之间的通信。 它位于 TCP 协议的上层,除了提供发布-订阅这一基本功能外,也提供一些其它特性:不同的消息投递保障(delivery guarantee),“至少一次”和“最多一次”。通过存储最后一个被确认接受的消息来实现重连后的消息恢复。
特点:它非常轻量级,并且从设计和实现层面都适合用于不稳定的网络环境中。
应用场景:物联网(IoT)场景中更适合,支持几乎所有语言进行开发,并且浏览器也可通过 WebSocket 来发送和接收 MQTT 消息。
activeMQ5.11.1版本带的例子提供了四种协议的简单demo,这四种协议分别为:AMQP,MQTT,OpenWire,Stomp,通过运行这四种协议的的demo可以大致得出这四种协议实现在activeMQ中的性能对比:
amqp
Received 10001 in 6.58 seconds
mqtt
Received 10000 in 2.69 seconds
openwire
Received 10001 in 8.87 seconds
stomp
Received 10001 in 14.17 seconds
amqp
Received 10001 in 6.58 seconds
mqtt
Received 10000 in 2.69 seconds
openwire
Received 10001 in 8.87 seconds
stomp
Received 10001 in 14.17 seconds
可以看出,mqtt协议的实现最快,stomp的协议实现最慢。