跳至主要内容
版本:4.0

STOMP 插件

概述

RabbitMQ 通过核心分发版中提供的插件支持 STOMP。该插件支持 STOMP 版本 1.0 到 1.2,具有一些 扩展和限制.

STOMP 客户端可以与其他协议互操作。管理 UI 中的所有功能以及其他几个插件可以与 STOMP 一起使用,尽管可能存在一些限制或需要调整默认设置。

启用插件

STOMP 插件包含在 RabbitMQ 分发版中。在客户端能够成功连接之前,必须使用 rabbitmq-plugins 启用它。

rabbitmq-plugins enable rabbitmq_stomp

插件配置

TCP 监听器

当未指定配置时,STOMP 适配器将在端口 61613 上的所有接口上监听,并具有默认用户登录名/密码 guest/guest

要更改监听器端口,请编辑您的 配置文件,以包含 rabbitmq_stomp 应用程序的 tcp_listeners 变量。

例如,一个最小化的配置文件,它将监听器端口更改为 12345,将如下所示:

stomp.listeners.tcp.1 = 12345

而将监听器更改为仅在本地主机上监听(对于 IPv4 和 IPv6)的配置文件将如下所示:

stomp.listeners.tcp.1 = 127.0.0.1:61613
stomp.listeners.tcp.2 = ::1:61613

TCP 监听器选项

该插件支持 TCP 监听器选项配置。

这些设置使用一个通用前缀 stomp.tcp_listen_options,并控制诸如 TCP 缓冲区大小、入站 TCP 连接队列长度、是否启用 TCP 保持活动 等内容。有关详细信息,请参阅 网络指南

stomp.listeners.tcp.1 = 127.0.0.1:61613
stomp.listeners.tcp.2 = ::1:61613

stomp.tcp_listen_options.backlog = 4096
stomp.tcp_listen_options.recbuf = 131072
stomp.tcp_listen_options.sndbuf = 131072

stomp.tcp_listen_options.keepalive = true
stomp.tcp_listen_options.nodelay = true

stomp.tcp_listen_options.exit_on_close = true
stomp.tcp_listen_options.send_timeout = 120

TLS 支持

要对 STOMP 连接使用 TLS,必须在代理中配置 TLS。要启用支持 TLS 的 STOMP 连接,请使用 stomp.listeners.ssl.* 配置键添加 STOMP 的 TLS 监听器。

该插件将使用核心 RabbitMQ 服务器证书和密钥(就像 AMQP 0-9-1 和 AMQP 1.0 监听器一样)。

ssl_options.cacertfile = /path/to/tls/ca_certificate.pem
ssl_options.certfile = /path/to/tls/server_certificate.pem
ssl_options.keyfile = /path/to/tls/server_key.pem
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = true

stomp.listeners.tcp.1 = 61613
# default TLS-enabled port for STOMP connections
stomp.listeners.ssl.1 = 61614

此配置在端口 61613 上创建一个标准 TCP 监听器,在端口 61614 上创建一个 TLS 监听器。

当设置了 TLS 监听器时,您可能希望停用所有非 TLS 监听器。这可以通过以下方式配置:

stomp.listeners.tcp   = none
stomp.listeners.ssl.1 = 61614

默认用户

RabbitMQ STOMP 适配器允许 CONNECT 帧在配置了默认值时省略 loginpasscode 标头。

要配置默认登录名和密码,请在 rabbitmq_stomp 应用程序配置中添加一个 default_user 部分。例如:

stomp.default_user = guest
stomp.default_pass = guest

上面的配置示例使 guest/guest 成为默认的登录名/密码对。

使用 TLS/x509 客户端证书进行身份验证

该插件可以通过从客户端的 TLS(x509)证书中提取名称来验证支持 TLS 的连接,而无需使用密码。

出于安全考虑,服务器必须使用 TLS 选项配置,将 fail_if_no_peer_cert 设置为 true,并将 verify 设置为 verify_peer,以强制所有 TLS 客户端都具有可验证的客户端证书。

要启用此功能,请为 rabbitmq_stomp 应用程序将 ssl_cert_login 设置为 true。例如:

stomp.ssl_cert_login = true

默认情况下,这会将用户名设置为证书主题的区分名称的 RFC4514 风格字符串形式,类似于 OpenSSL 的 "-nameopt RFC2253" 选项所生成的字符串形式。

要使用通用名称,请添加:

ssl_cert_login_from = common_name

到您的配置中。

请注意:

  • 已验证的用户必须存在于配置的身份验证/授权后端中。
  • 客户端不能提供 loginpasscode 标头。

隐式连接

如果您配置了默认用户或使用 SSL 客户端证书身份验证,您还可以选择允许客户端完全省略 CONNECT 帧。在这种模式下,如果会话上发送的第一个帧不是 CONNECT,则客户端会自动以默认用户或 SSL 证书中提供的用户身份连接。

要启用隐式连接,请为 rabbit_stomp 应用程序将 implicit_connect 设置为 true。例如:

stomp.default_user = guest
stomp.default_pass = guest
stomp.implicit_connect = true

隐式连接不是默认启用的。

注意:导致隐式连接的客户端不会从服务器接收 CONNECTED 帧。

代理协议

STOMP 插件支持 代理协议。默认情况下,此功能处于关闭状态。要为 STOMP 客户端启用它:

stomp.proxy_protocol = true

有关代理协议的更多信息,请参阅 网络指南

帧大小限制

默认情况下,帧大小限制为 4Mb。当帧超过限制时,将发生错误并关闭连接。

stomp.max_frame_size = 4 * 1024 * 1024

目标

STOMP 规范没有规定代理必须支持哪些目标类型,而是 SENDMESSAGE 帧中 destination 标头的值是代理特定的。RabbitMQ STOMP 适配器支持多种不同的目标类型:

  • /exchange -- SEND 到任意路由键,SUBSCRIBE 到任意绑定模式;
  • /queue -- SENDSUBSCRIBE 到由 STOMP 网关管理的队列;
  • /amq/queue -- SENDSUBSCRIBE 到在 STOMP 网关之外创建的队列;
  • /topic -- SENDSUBSCRIBE 到瞬时和持久主题;
  • /temp-queue/ -- 创建临时队列(仅在 reply-to 标头中)。

AMQP 0-9-1 语义

MESSAGE 帧上的 destination 标头设置为好像该消息来自 SEND 帧一样

  • 发布到默认交换机的消息将被赋予目标 /queue/queuename
  • 发布到 amq.topic 的消息将被赋予目标 /topic/routing_key
  • 所有其他消息将被赋予目标 /exchange/exchange_name[/routing_key]。

如果 queuenameexchange_namerouting_key 中包含 /% 或非 ASCII 字节,则它们将分别被替换为序列 %dd,其中 dd 是字节的十六进制代码。

由于这些规则,MESSAGE 帧上的目标可能与发布它的 SEND 上的目标不完全匹配。

不同的目标具有不同的队列参数默认值。它们可以通过标头显式控制,本指南将进一步解释。

交换目标

可以使用以 /exchange 为前缀的目标访问任何交换机/队列或交换机/路由键组合。

对于 SUBSCRIBE 帧,可以使用 /exchange/<name>[/<pattern>] 形式的目标。此目标

  • <name> 交换机上创建一个独占的、自动删除的队列;
  • 如果提供了 <pattern>,则使用 <pattern> 将队列绑定到 <name> 交换机;并且
  • 为当前 STOMP 会话注册针对该队列的订阅。

对于 SEND 帧,可以使用 /exchange/<name>[/<routing-key>] 形式的目标。此目标

  • 将消息发送到交换机 <name>,路由键为 <routing-key>

注意:交换目标适合从现有队列中消费消息。每个订阅者都会创建一个新队列,并使用提供的路由键将其绑定到指定的交换机。要使用现有队列,请使用 /amq/queue 目标。

队列目标

对于简单队列,可以使用 /queue/<name> 形式的目标。

队列目标最多将每条消息传递给一个订阅者。在没有订阅者存在的情况下发送的消息将被排队,直到订阅者连接到该队列。

AMQP 0-9-1 语义

对于 SUBSCRIBE 帧,这些目标将创建一个共享队列 <name>。将为当前 STOMP 会话创建一个针对队列 <name> 的订阅。

对于 SEND 帧,将在本会话中首次SEND 到此目标时创建一个共享队列 <name>,但不会在后续操作中创建。该消息将发送到默认交换机,路由键为 <name>

如果没有指定任何队列参数,将假定队列是持久性的、非独占的、非自动删除的。

AMQ 队列目标

为了解决在 STOMP 适配器外部创建的现有队列,可以使用 /amq/queue/<name> 格式的目标。

AMQP 0-9-1 语义

对于 SENDSUBSCRIBE 帧,都不会创建队列。对于 SUBSCRIBE 帧,如果队列不存在,则会发生错误。

对于 SEND 帧,消息将通过默认交换机直接发送到名为 <name> 的现有队列。

对于 SUBSCRIBE 帧,将在当前 STOMP 会话中针对现有队列 <name> 创建一个订阅。

如果没有指定任何队列参数,将假定队列是持久性的、非独占的、非自动删除的。

主题目标

STOMP 客户端最常用的目标类型可能是 /topic/<name>。它们在发布消息时对订阅者模式执行主题匹配,并且可以将消息路由到多个订阅者(每个订阅者都会收到自己的副本)。主题目标支持 AMQP 0-9-1 主题交换机 的所有路由模式。

发送到没有活动订阅者的主题目标的消息将被简单地丢弃。

AMQP 0-9-1 语义

对于 SEND 帧,消息将发送到 amq.topic 交换机,路由键为 <name>

对于 SUBSCRIBE 帧,将创建一个自动删除的、非持久化的队列,并将它绑定到 amq.topic 交换机,路由键为 <name>。针对该队列创建了一个订阅。

可以使用 stomp.default_topic_exchange 配置设置指定一个与 amq.topic 不同的默认交换机。

stomp.default_topic_exchange = some.exchange

持久化主题订阅

STOMP 适配器支持持久化主题订阅。持久化订阅允许客户端根据需要断开与 STOMP 代理的连接并重新连接,而不会错过发送到主题的消息。

主题既不持久也不瞬时,而是订阅是持久或瞬时的。持久和瞬时可以针对给定主题进行混合。

创建持久化订阅

要创建持久化订阅,请在 SUBSCRIBE 帧中将 durable 标头设置为 truepersistent 也作为 durable 的别名支持,以向后兼容之前的插件版本。

在为主题目标创建持久化订阅时,请将 auto-delete 设置为 false,以确保在最后一个订阅者断开连接时不会删除支持订阅的队列。

在创建持久化订阅时,必须指定 id 标头。例如

SUBSCRIBE
destination:/topic/my-durable
id:1234
durable:true
auto-delete:false

AMQP 0-9-1 语义

对于 SEND 帧,消息将发送到 amq.topic 交换机,路由键为 <name>

对于 SUBSCRIBE 帧,将为每个不同的订阅 ID x 目标对创建一个共享队列,并将其绑定到 amq.topic 交换机,路由键为 <name>。针对该队列创建了一个订阅。

注意:可以使用 stomp.default_topic_exchange 配置设置指定一个与 amq.topic 不同的默认交换机。

删除持久化订阅

要永久删除持久化订阅,请针对订阅 ID 发送一个 UNSUBSCRIBE 帧,该帧具有与订阅时相同的 durableauto-delete 标头值。

例如

UNSUBSCRIBE
id:1234
durable:true
auto-delete:false

临时队列目标

临时队列目标允许你在 SEND 帧的 reply-to 标头中定义临时目标。

临时队列由代理管理,它们的标识对每个会话都是私有的——在不同的会话中,无需为临时队列选择不同的名称。

要使用临时队列,请将 reply-to 标头放在 SEND 帧上,并使用以 /temp-queue/ 开头的标头值。例如

SEND
destination:/queue/reply-test
reply-to:/temp-queue/foo

Hello World!

此帧将创建一个对会话私有的临时队列(使用生成的名称),并自动订阅该队列。使用 reply-to:/temp-queue/foo 的另一个会话将创建一个新的、不同的队列。

内部订阅 ID 是字符串 /temp-queue/ 和临时队列的串联(在本例中为 /temp-queue/foo)。订阅 ID 可用于识别回复消息。无法从 destination 标头中识别回复消息,该标头将与 reply-to 标头中的值不同。内部订阅使用自动确认模式,无法取消。

/temp-queue/ 目标不是接收客户端在发送回复时使用的目标的名称。相反,接收客户端可以从 MESSAGE 帧的 reply-to 标头中获取(真实的)回复目标队列名称。然后,此回复目标名称可用作发送到接收到的 MESSAGE 的回复中的 SEND 帧的 destination 标头中的值。

回复目标队列名称是不透明的,无法从 /temp-queue/ 名称推断。

SENDSUBSCRIBE不得destination 标头中包含 /temp-queue 目标。无法发送到 /temp-queue 目标的消息,并且会自动创建对回复队列的订阅。

AMQP 0-9-1 语义

每个 /temp-queue/ 都对应一个不同的匿名、排他的、自动删除的队列。因此,无需显式清理回复队列。

用于主题和交换机目标的用户生成的队列名称

在订阅 exchangetopic 目标时,RabbitMQ 会默认生成一个队列名称。可以使用 x-queue-name 标头提供自定义名称

SUBSCRIBE
destination:/topic/alarms
x-queue-name:my-alarms-queue

使用 STOMP 控制 RabbitMQ 队列参数

队列属性 可以通过 STOMP 标头进行控制

  • durable(别名为 persistent
  • auto-delete
  • exclusive

以及用于控制死信传递、队列和消息 TTL、队列限制等的可选参数(“x-arguments”)

  • x-dead-letter-exchange
  • x-dead-letter-routing-key
  • x-expires
  • x-message-ttl
  • x-max-length
  • x-max-length-bytes
  • x-max-age(仅适用于
  • x-stream-max-segment-size-bytes(仅适用于
  • x-overflow
  • x-max-priority
  • x-queue-type(能够 声明 仲裁队列

每个标头的含义与通过 AMQP 0-9-1 声明队列时相同。有关详细信息,请参阅其余文档。

在 STOMP 中使用策略

RabbitMQ 策略 允许灵活地集中配置队列和交换机的属性。策略可用于 STOMP 插件使用的队列。

策略使 STOMP 可以使用更多 RabbitMQ 功能

STOMP 插件创建的所有服务器命名的队列都以 stomp- 为前缀,这使得在策略中轻松匹配队列。例如,要将 STOMP 队列长度限制为 1000 条消息,请创建以下策略

rabbitmqctl set_policy stomp-queues "^stomp-" '{"max-length":1000}' --apply-to queues

在 Windows 上使用 rabbitmqctl.bat

rabbitmqctl.bat set_policy stomp-queues "^stomp-" "{""max-length"":1000}" --apply-to queues

注意,一次只能将一个策略应用于一个队列,因此要指定多个参数(例如队列长度限制和死信传递),需要将它们放到一个策略中。

协议扩展和限制

RabbitMQ STOMP 适配器会放宽 CONNECT 上的协议,并在某些帧上支持一些非标准标头。这些额外的标头提供对 STOMP 规范中未描述的功能的访问权限。此外,我们禁止某些为服务器保留的标头。详细信息如下。

连接和虚拟主机

STOMP 1.1 中的 CONNECT(或 STOMP)帧有一个强制性的 host 标头(用于选择用于连接的虚拟主机)。RabbitMQ 适配器允许它是可选的。

如果省略,则假定默认虚拟主机(/)。要配置不同的默认虚拟主机,请在 rabbitmq_stomp 应用程序配置中添加一个 default_vhost 部分,例如

stomp.default_vhost = /

如果指定了 host 标头,它必须是 RabbitMQ 服务器已知的虚拟主机之一,否则连接将被拒绝。即使在连接时协商了 STOMP 1.0 版本,也会尊重 host 标头。

消息持久性

SEND 帧上,STOMP 适配器支持包含 persistent 标头。

persistent 标头设置为 true 会使消息持久化。

在收到来自代理的确认之前,不会发送带有 persistent:trueSEND 帧的回执。可以在 此处 找到有关持久化消息确认的确切语义。

持久化消息的 MESSAGE 帧将包含 persistent:true 标头。

ACK 和 NACK

RabbitMQ STOMP 插件支持 autoclientclient-individual 订阅标头,这些标头会影响 ACKNACK 操作的工作方式。

auto 模式使用自动确认。client 模式是手动(由客户端驱动)确认多条消息。client-individual 用于逐条消息手动确认。

NACK 帧可以选择携带 requeue 标头,该标头控制消息将被重新排队还是被丢弃/死信传递。默认值为 true

预取

默认情况下,所有订阅的预取计数都设置为无限制。可以通过在 SUBSCRIBE 帧上将 prefetch-count 标头设置为所需的整数计数来控制它。

流支持

SUBSCRIBE 帧支持一个 x-stream-offset 头部,用于指定在 中开始消费的偏移量。一个典型的流订阅帧如下所示:

SUBSCRIBE
destination:/amq/queue/my-stream
ack:client
prefetch-count:10
x-stream-offset:next

请注意,ackprefetch-count 头部也是必要的。x-stream-offset 头部与 AMQP 0.9.1 中的语义相同,可能的值有:

  • first,从流中第一个可用的消息开始消费
  • last,从最后一个写入的消息块开始消费
  • next,从流的末尾开始消费(注意,在有人发布到流之前,消费者不会收到消息)
  • offset=<offset-value>,从特定偏移量开始,例如 offset=40000
  • timestamp=<unix-time>,从给定时间开始,例如 timestamp=1619432061 代表 2021-04-26T10:14:21+00:00

默认值为 next

从流中传递消息时,消息偏移量(即消息在流中的位置)包含在 MESSAGE 帧的 x-stream-offset 头部中。

流过滤 也受支持。 流协议 是与流交互的首选方式,但大多数功能也可以使用其他协议实现。流过滤也不例外,它在 STOMP 中的工作方式与 AMQP 中相同。

  • 声明:流可以在订阅时创建。将 x-queue-type 头部设置为 stream,并使用 x-stream-filter-size-bytes 头部设置过滤器大小(可选)。
  • 发布:使用 x-stream-filter-value 头部设置出站消息的过滤器值。
  • 消费:使用 x-stream-filter 头部设置预期的过滤器值(使用逗号分隔多个值),并可选地使用 x-stream-match-unfiltered 头部(truefalse)接收没有过滤器值的消息(默认值为 false)。应用程序还必须实现客户端过滤,因为仍然可能收到不符合过滤器值标准的消息。

SEND 上禁止的头部

不允许在 SEND 帧上设置 message-id 头部。头部及其值由服务器在发送给客户端的 MESSAGE 帧上设置。

队列属性

SEND 帧还允许对应于发布消息时可用的AMQP 属性的头部。这些头部也会在发送给客户端的 MESSAGE 帧上设置。

所有未被弃用的 AMQP 0-9-1 属性(content-typecontent-encodingheadersdelivery-modeprioritycorrelation-idreply-toexpirationmessage-idtimestamptypeuser-idapp-id)都受支持。以下特殊规则适用:

  • STOMP 中的 amqp-message-id 会转换为 AMQP 中的 message-id,反之亦然。
  • reply-to 头部会导致创建临时队列(参见上文 临时队列目标)。
  • 一些以 x 开头的 STOMP 头部会转换为可选的队列参数(见下文)。

可选队列属性

在 RabbitMQ 中,SENDSUBSCRIBE 帧可以包含一组头部来配置队列行为,例如,使用 TTL 或类似的扩展。

支持的头部列表如下:

例如,如果你想使用 STOMP 的优先级队列,可以使用以下头部进行订阅(或发送):

SUBSCRIBE
destination:/queue/my-priority-queue
x-max-priority:5

队列不可变性

一旦声明了队列,其属性就无法更改。可选参数可以使用 策略 修改。否则,队列必须被删除并重新声明。这对于 STOMP 客户端和 AMQP 0-9-1 都是一样的。

© 2024 RabbitMQ. All rights reserved.