WebSocket 上的 AMQP 1.0
我们很高兴地宣布在 VMware Tanzu RabbitMQ 4.1 中支持 WebSocket 上的 AMQP 1.0。
此功能使任何基于浏览器的应用程序都能够使用 AMQP 1.0 与 RabbitMQ 进行通信,为广泛的高效基于浏览器的业务消息传递场景铺平了道路。
什么是 WebSocket?
RFC 6455 中定义的 WebSocket 是一个简单的协议,包含两个部分。
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 连接到 RabbitMQ,使用 MQTT 或 STOMP。WebSocket 上的 AMQP 带来了以下好处:
- 功能丰富:与专为简洁设计的 MQTT 和 STOMP 不同,AMQP 是一个专为业务消息传递设计的协议,支持更高级的功能。
- 效率:AMQP 是二进制且高效的,而 STOMP 是面向文本的。
这使得 WebSocket 上的 AMQP 成为高效、功能丰富的基于浏览器的业务消息传递的绝佳选择。
WebSocket 代理
在此插件出现之前,一种变通方法是使用 WebSocket 代理。代理会接受来自客户端的 WebSocket 连接,并与 RabbitMQ 建立单独的 TCP 连接。虽然功能可用,但这种方法带来了缺点,例如:
- 额外的网络跳数带来的延迟增加。
- 维护每个客户端的两个 TCP 连接会增加资源使用。
- 部署和监控代理的运维开销。
- 额外的潜在故障点。
新插件通过提供直接的 WebSocket 上的 AMQP 支持消除了这些问题。
示例
RabbitMQ 包含 rabbitmq_web_stomp_examples 和 rabbitmq_web_mqtt_examples 插件,其中包含称为 “echo” 和 “bunny” 的基本示例。同样,VMware Tanzu RabbitMQ 4.1 引入了 rabbitmq_web_amqp_examples。
WebSocket 上的 AMQP “bunny” 示例工作方式如下:
rabbitmq_web_amqp_examples插件创建了一个名为amq.web_amqp_examples.bunny的 流。- 访问
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 连接,还创建了一个 会话 和到预先声明的流的 链接。
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 特有的功能,例如声明 交换、队列 和 绑定。
总结
VMware Tanzu RabbitMQ 4.1 使浏览器能够使用 AMQP 1.0 与 RabbitMQ 进行通信。
请注意:新的 WebSocket 上的 AMQP 插件是一项闭源功能,仅在商业版 VMware Tanzu RabbitMQ 中提供。它不属于开源 RabbitMQ 发行版。
虽然这篇博文用一个有趣的兔子示例来说明了这项功能,但 AMQP 1.0 是一个为业务消息传递而构建的高效协议。可以想象一下企业级工具,如 Salesforce、Workday 或 Jira - 它们都运行在浏览器中,并受益于实时消息传递。
