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
而将监听器更改为仅在 localhost 上(对于 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 Keep-Alive 等。 有关详细信息,请参阅网络指南。
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 支持
要将 TLS 用于 STOMP 连接,必须在 broker 中配置 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
帧省略 login
和 passcode
标头。
要配置默认登录名和密码,请将 default_user
部分添加到 rabbitmq_stomp
应用程序配置。 例如
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
到您的配置中。
请注意
- 经过身份验证的用户必须存在于配置的身份验证/授权后端中。
- 客户端**不得**提供
login
和passcode
标头。
隐式连接
如果配置了默认用户或使用 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 规范未规定 broker 必须支持的目的地类型,而是 SEND
和 MESSAGE
帧中 destination
标头的值是 broker 特有的。 RabbitMQ STOMP 适配器支持多种不同的目的地类型
/exchange
--SEND
到任意路由键,以及SUBSCRIBE
到任意绑定模式;/queue
--SEND
和SUBSCRIBE
到由 STOMP 网关管理的队列;/amq/queue
--SEND
和SUBSCRIBE
到在 STOMP 网关外部创建的队列;/topic
--SEND
和SUBSCRIBE
到瞬态和持久性主题;/temp-queue/
-- 创建临时队列(仅在reply-to
标头中)。
AMQP 0-9-1 语义
MESSAGE
帧上的 destination
标头的设置方式与消息源自 SEND
帧的方式相同
- 发布到默认交换机的消息被赋予目的地
/queue/
queuename; - 发布到
amq.topic
的消息被赋予目的地/topic/
routing_key; - 所有其他消息都被赋予目的地
/exchange/
exchange_name[/
routing_key]。
如果 queuename、exchange_name 或 routing_key 中存在 /
、%
或非 ASCII 字节,则它们都将替换为序列 %
dd,其中 dd 是字节的十六进制代码。
由于这些规则,MESSAGE
帧上的目的地可能与发布它的 SEND
帧上的目的地不完全匹配。
不同的目的地具有不同的队列参数默认值。 可以通过标头显式控制它们,如本指南稍后所述。
交换机目的地
可以使用以 /exchange
为前缀的目的地访问任何交换机/队列或交换机/路由键组合。
对于 SUBSCRIBE
帧,可以使用 /exchange/<name>[/<pattern>]
形式的目的地。 此目的地
- 在
<name>
交换机上创建独占、自动删除队列; - 如果提供了
<pattern>
,则使用<pattern>
将队列绑定到<name>
交换机;以及 - 针对当前 STOMP 会话的队列注册订阅。
对于 SEND
帧,可以使用 /exchange/<name>[/<routing-key>]
形式的目的地。 此目的地
- 使用路由键
<routing-key>
发送到交换机<name>
。
**注意:** 交换机目的地不适用于从现有队列消费消息。 为每个订阅者创建一个新队列,并使用提供的路由键绑定到指定的交换机。 要使用现有队列,请使用 /amq/queue
目的地。
队列目的地
对于简单队列,可以使用 /queue/<name>
形式的目的地。
队列目的地最多将每条消息传递给一个订阅者。 当没有订阅者存在时发送的消息将被排队,直到订阅者连接到队列。
AMQP 0-9-1 语义
对于 SUBSCRIBE
帧,这些目的地创建共享队列 <name>
。 针对当前 STOMP 会话的队列 <name>
创建订阅。
对于 SEND
帧,共享队列 <name>
在此会话中首次 SEND
到此目的地时创建,但随后不会创建。 消息使用路由键 <name>
发送到默认交换机。
如果未指定队列参数,则队列将被假定为持久、非独占、非自动删除。
AMQ 队列目的地
要寻址在 STOMP 适配器外部创建的现有队列,可以使用 /amq/queue/<name>
形式的目的地。
AMQP 0-9-1 语义
对于 SEND
和 SUBSCRIBE
帧,都不会创建队列。 对于 SUBSCRIBE
帧,如果队列不存在,则会出错。
对于 SEND
帧,消息通过默认交换机直接发送到名为 <name>
的现有队列。
对于 SUBSCRIBE
帧,针对当前 STOMP 会话的现有队列 <name>
创建订阅。
如果未指定队列参数,则队列将被假定为持久、非独占、非自动删除。
主题目的地
/topic/<name>
可能是 STOMP 客户端使用的最常见的目的地类型。 它们对发布消息与订阅者模式执行主题匹配,并且可以将消息路由到多个订阅者(每个订阅者都获得自己的副本)。 主题目的地支持 AMQP 0-9-1 主题交换机的所有路由模式。
发送到没有活动订阅者主题目的地的消息将被简单地丢弃。
AMQP 0-9-1 语义
对于 SEND
帧,消息使用路由键 <name>
发送到 amq.topic
交换机。
对于 SUBSCRIBE
帧,将创建一个自动删除的、非持久性队列,并使用路由键 <name>
绑定到 amq.topic
交换机。 针对队列创建一个订阅。
可以使用 stomp.default_topic_exchange
配置设置指定与 amq.topic
不同的默认交换机
stomp.default_topic_exchange = some.exchange
持久主题订阅
STOMP 适配器支持持久主题订阅。 持久订阅允许客户端根据需要断开连接并重新连接到 STOMP broker,而不会丢失发送到主题的消息。
主题既不是持久的也不是瞬态的,而是订阅是持久的或瞬态的。 持久和瞬态可以针对给定的主题混合使用。
创建持久订阅
要创建持久订阅,请在 SUBSCRIBE
帧中将 durable
标头设置为 true
。 persistent
也作为 durable
的别名受到支持,以便向后兼容早期插件版本。
在创建到主题目的地的持久订阅时,将 auto-delete
设置为 false
,以确保当最后一个订阅者断开连接时,支持您的订阅的队列不会被删除。
创建持久订阅时,必须指定 id
标头。 例如
SUBSCRIBE
destination:/topic/my-durable
id:1234
durable:true
auto-delete:false
AMQP 0-9-1 语义
对于 SEND
帧,消息使用路由键 <name>
发送到 amq.topic
交换机。
对于 SUBSCRIBE
帧,为每个不同的订阅 ID x 目的地对创建一个共享队列,并使用路由键 <name>
绑定到 amq.topic
交换机。 针对队列创建一个订阅。
注意: 可以使用 stomp.default_topic_exchange
配置设置指定与 amq.topic
不同的默认交换机。
删除持久订阅
要永久删除持久订阅,请为订阅 ID 发送一个 UNSUBSCRIBE
帧,其 durable
和 auto-delete
标头值与订阅时相同。
例如
UNSUBSCRIBE
id:1234
durable:true
auto-delete:false
临时队列目的地
临时队列目的地允许您在 SEND
帧的 reply-to
标头中定义临时目的地。
临时队列由 broker 管理,并且它们的身份对于每个会话都是私有的 - 无需为不同会话中的临时队列选择不同的名称。
要使用临时队列,请在 SEND
帧上放置 reply-to
标头,并使用以 /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/
名称推断出来。
SEND
和 SUBSCRIBE
帧不得在 destination
标头中包含 /temp-queue
目的地。 消息无法发送到 /temp-queue
目的地,并且回复队列的订阅是自动创建的。
AMQP 0-9-1 语义
每个 /temp-queue/
都对应于一个不同的匿名、独占、自动删除队列。 因此,无需显式清理回复队列。
主题和交换机目的地的用户生成队列名称
当订阅 exchange
或 topic
目的地时,RabbitMQ 默认会生成一个队列名称。 可以使用 x-queue-name
标头提供自定义名称
SUBSCRIBE
destination:/topic/alarms
x-queue-name:my-alarms-queue
使用 STOMP 控制 RabbitMQ 队列参数
队列属性可以通过 STOMP 标头进行控制
durable
(别名为persistent
)自动删除
独占
以及用于控制死信、队列和消息 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 插件使用的队列一起使用。
策略使得可以将更多 RabbitMQ 功能与 STOMP 一起使用
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 适配器允许它是可选的。
省略时,假定为默认虚拟主机 (/
)。 要配置不同的默认虚拟主机,请将 default_vhost
部分添加到 rabbitmq_stomp
应用程序配置,例如
stomp.default_vhost = /
如果指定了 host
标头,则它必须是 RabbitMQ 服务器已知的虚拟主机之一,否则连接将被拒绝。 即使在连接时协商了 STOMP 1.0 版本,host
标头也会受到尊重。
消息持久性
在 SEND
帧上,STOMP 适配器支持包含 persistent
标头。
将 persistent
标头设置为 true
具有使消息持久化的效果。
在收到来自 broker 的确认之前,不会发送 persistent:true
的 SEND
帧的回执。 有关持久消息确认的确切语义,请参见此处。
持久消息的 MESSAGE
帧将包含 persistent:true
标头。
ACK 和 NACK
RabbitMQ STOMP 插件支持影响 ACK
和 NACK
操作方式的 auto
、client
和 client-individual
订阅标头。
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
请注意,ack
和 prefetch-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
标头(true
或false
)来接收没有任何过滤器值的消息(默认为false
)。 应用程序还必须实现客户端过滤,因为仍然可能收到不符合过滤器值条件的消息。
SEND
上禁止的标头
不允许在 SEND
帧上设置 message-id
标头。 标头及其值由服务器在发送到客户端的 MESSAGE
帧上设置。
队列属性
SEND
帧还允许与发布消息时可用的AMQP 属性对应的标头。 这些标头也在发送到客户端的 MESSAGE
帧上设置。
支持所有未弃用的 AMQP 0-9-1 属性(content-type
、content-encoding
、headers
、delivery-mode
、priority
、correlation-id
、reply-to
、expiration
、message-id
、timestamp
、type
、user-id
和 app-id
)。 以下特殊规则适用
- STOMP 中的
amqp-message-id
将转换为 AMQP 中的message-id
,反之亦然。 reply-to
标头会导致创建临时队列(请参阅上面的 临时队列目的地)。- 一些以 x 为前缀的 STOMP 标头会转换为可选的队列参数(见下文)。
可选队列属性
使用 RabbitMQ,SEND
和 SUBSCRIBE
帧可以包含一组标头来配置队列行为,例如,使用 TTL 或类似的扩展。
支持的标头列表为
- x-message-ttl
- x-expires
- x-max-length
- x-max-length-bytes
- x-dead-letter-exchange
- x-dead-letter-routing-key
- x-max-priority
例如,如果您想将优先级队列与 STOMP 一起使用,则可以使用以下标头进行 SUBSCRIBE(或 SEND)
SUBSCRIBE
destination:/queue/my-priority-queue
x-max-priority:5
队列不变性
一旦声明队列,其属性就无法更改。 可选参数可以使用策略进行修改。 否则,队列必须被删除并重新声明。 这对于 STOMP 客户端以及 AMQP 0-9-1 都是如此。