WebSocket 上的 AMQP 1.0
我们很高兴地宣布在 VMware Tanzu RabbitMQ 4.1 中支持 WebSocket 上的 AMQP 1.0。
此功能使任何基于浏览器的应用程序都能够使用 AMQP 1.0 与 RabbitMQ 进行通信,为广泛的高效基于浏览器的业务消息传递场景铺平了道路。
什么是 WebSocket?
WebSocket 定义于 RFC 6455,是一个包含两部分的简单协议。
Client Server
| |
|================ Part I =================|
|---- WebSocket Handshake Request ------->|
| GET /some/path HTTP/1.1 |
| Upgrade: websocket |
| Connection: Upgrade |
| Sec-WebSocket-Protocol: amqp |
| |
|<-- WebSocket Handshake Response --------|
| HTTP/1.1 101 Switching Protocols |
| Upgrade: websocket |
| Connection: Upgrade |
| Sec-WebSocket-Protocol: amqp |
| |
|================ Part II ================|
|<========= WebSocket Connection ========>|
| Full-duplex communication |
| |
|<---------- Binary Data [AMQP] --------->|
|<---------- Binary Data [AMQP] --------->|
|<---------- Binary Data [AMQP] --------->|
| ... |
| |
|----------- Close Frame ---------------->|
|<---------- Close Frame -----------------|
第一部分是握手,由 HTTP 请求和响应组成。第二部分是数据传输:客户端和服务器之间保持单个 TCP 连接打开,允许双方随时向对方推送二进制数据。
在本例中,二进制数据由 AMQP 帧组成,因为客户端向服务器提出了 Sec-WebSocket-Protocol: amqp,并且服务器接受了该协议。Sec-WebSocket-Protocol 标头指定了叠加在 WebSocket 之上的应用层协议。
该通信的协议栈如下所示
+-------------------+
| AMQP | Application Layer
+-------------------+
| WebSocket |
+-------------------+
| TCP | Transport Layer
+-------------------+
| IP | Network Layer
+-------------------+
| Ethernet | Link Layer
+-------------------+
WebSocket 协议本身并不限定应用层协议,这使其具有灵活性。它可以支持任何协议,包括 STOMP 和 MQTT。
为什么选择 WebSocket?
WebSocket 具有以下优势:
- 浏览器兼容性:它允许基于浏览器的应用程序使用 HTTP 以外的应用层协议。出于安全原因,浏览器限制 JavaScript 打开原始 TCP 连接来使用 AMQP 或 MQTT 等协议。WebSocket 可以防止在浏览器中运行的恶意 JavaScript,从而实现基于 WebSocket 层的安全应用层通信。
- 防火墙穿透:WebSocket 有助于在具有限制性防火墙规则的环境中进行通信。例如,虽然端口 443 (
https) 可能被允许,但用于amqps的端口 5671 可能会被阻止。在这种情况下,可以使用端口 443 上的安全 WebSocket (wss) 连接来通过 AMQP 进行通信。
现代浏览器普遍支持 WebSocket,使其成为基于 Web 的应用程序的实用选择。
RabbitMQ 中的 WebSocket
长期以来,RabbitMQ 分别通过 rabbitmq_web_stomp 和 rabbitmq_web_mqtt 插件支持 WebSocket 上的 STOMP 和 WebSocket 上的 MQTT。
VMware Tanzu RabbitMQ 4.1 引入了新的 rabbitmq_web_amqp 插件,该插件符合 AMQP WebSocket 绑定委员会规范 01。此插件的运行方式与现有的 WebSocket 插件类似,通过启动侦听器来管理 WebSocket 协议相关的方面。
此前,基于浏览器的应用程序通常由于缺乏 AMQP 支持而使用 WebSocket 上的 MQTT 或 STOMP 连接到 RabbitMQ。WebSocket 上的 AMQP 带来了以下好处:
- 功能丰富:与旨在追求简洁的 MQTT 和 STOMP 不同,AMQP 是一种专为商业消息传递而设计的协议,支持更多高级功能。
- 高效:AMQP 是二进制且高效的,而 STOMP 是面向文本的。
这使得 WebSocket 上的 AMQP 成为高效、功能丰富的浏览器端商业消息传递的绝佳选择。
WebSocket 中继
在此插件发布之前,一种变通方法是使用 WebSocket 中继(Relay)。中继会接受来自客户端的 WebSocket 连接,并打开单独的 TCP 连接到 RabbitMQ。虽然可行,但这种方法存在以下弊端:
- 额外的网络跳数导致的延迟增加。
- 为每个客户端维持两个 TCP 连接导致资源使用量增加。
- 部署和监控中继的运维开销。
- 潜在的额外故障点。
新插件通过提供直接的 WebSocket 上的 AMQP 支持消除了这些问题。
示例
RabbitMQ 包含了带有名为 “echo” 和 “bunny” 的基础示例的 rabbitmq_web_stomp_examples 和 rabbitmq_web_mqtt_examples 插件。同样,VMware Tanzu RabbitMQ 4.1 也引入了 rabbitmq_web_amqp_examples。
WebSocket 上的 AMQP “bunny” 示例工作流程如下:
rabbitmq_web_amqp_examples插件创建一个名为amq.web_amqp_examples.bunny的 流 (stream)。- 当访问
https://:15670/web-amqp-examples/bunny.html时,插件会提供bunny.html、bunny.png和rhea.js文件。bunny.html文件显示bunny.png。此外,bunny.html文件包含 JavaScript 代码,用于从浏览器创建到 RabbitMQ 的 WebSocket 上的 AMQP 连接。
// default AMQP over WebSocket port and path in RabbitMQ
var url = "ws://" + location.hostname + ":15678/ws"
var ws = client.websocket_connect(WebSocket);
var connection = client.connect({
"connection_details":ws(url, ["amqp"]),
// Setting username without password causes rhea to use SASL mechanism ANONYMOUS.
"username": "ignored",
});
此代码片段使用了 rhea.js 文件。rhea 是一个开源的 AMQP 1.0 TypeScript/JavaScript 库。通过在 rhea 仓库的根目录中运行以下命令,可以创建此单一文件:
npm install
make browserify
浏览器不仅打开了 WebSocket 上的 AMQP 连接,还创建了一个 会话 (session) 以及指向预声明流或从流中引出的 链接 (links)。
var address = "/queues/" + stream
client.on("connection_open", function (context) {
sender = context.connection.open_sender(address);
// If we open a new brower tab, we want to see the existing drawing.
const filter = {'my-filter': amqp_types.wrap_described("first", "rabbitmq:stream-offset-spec")};
context.connection.open_receiver({source:{address: address, filter: filter}});
});

- 如果您在相同的 URL 下打开第二个浏览器标签页,它也会创建一个向同一流发布并从中消费的 WebSocket 上的 AMQP 连接。
- 当您在两个浏览器标签页中的任何一个上进行绘画时,另一个标签页会看到实时绘图,因为两个标签页都从同一个流中进行消费。

客户端
作为 rhea 的替代方案,您可以使用 RabbitMQ AMQP 1.0 JavaScript 库。正如在 原生 AMQP 1.0 博客文章中所述,RabbitMQ 库包含 RabbitMQ 特定的功能,例如声明 交换机 (exchanges)、队列 (queues) 和 绑定 (bindings)。
总结
VMware Tanzu RabbitMQ 4.1 使浏览器能够使用 AMQP 1.0 与 RabbitMQ 进行通信。
请注意:新的 WebSocket 上的 AMQP 插件是一项闭源功能,仅在商业化的 VMware Tanzu RabbitMQ 产品中提供。它不属于开源 RabbitMQ 发行版的一部分。
虽然这篇博客文章通过一个有趣的兔子示例来说明该功能,但 AMQP 1.0 是一种专为商业消息传递而构建的高效协议。想想 Salesforce、Workday 或 Jira 等企业工具——它们都在浏览器中运行,并能从实时消息传递中获益。
