ApacheMQ Artemis 保留没有路由的消息
ApacheMQ Artemis keep messages with no route
我只使用 Artemis 2.6.2
和 STOMP 以及以下星座:
经纪人:
- 在 broker.xml 中没有配置 queue,一切都是自动创建的。
服务器:
- 订阅目的地
TaskResponse
没有 selector/filter
- 使用 header clientId = ID(服务器请求的客户端 ID)发送到目的地
TaskRequest
客户端 123:
- 使用选择器 clientId = 123
订阅目的地 TaskRequest
- 使用 header clientId = 123
发送到目的地 TaskResponse
当我在 Artemis Console
观看时,会发生以下情况:
没有连接服务器和客户端:没有地址或 queue 存在
服务器连接:Artemis
创建多播地址 TaskResponse
并为此地址创建多播 queue,过滤器为空
客户端 123 连接:Artemis
创建多播地址 TaskRequest
并为此地址创建多播 queue,过滤器 clientId = 123
消息交换:消息按预期从服务器传输到客户端并返回服务器。
客户端 123 断开连接:Artemis
删除多播地址 TaskRequest
和对应的多播 queue,过滤器 clientId = 123
服务器向客户端 123 的 TaskRequest 发送消息:根据服务器上的 STOMP
客户端消息发送成功。在代理上,消息消失了。
反之亦然:客户端 123 已连接,服务器未连接:根据客户端 123 上的 STOMP
客户端,消息发送成功。在代理上,消息消失了。
我的猜测是消息被丢弃是因为没有到订阅者的路由。如果我在 broker.xml 的 address-settings 部分启用选项 "send-to-dla-on-no-route",消息将直接转到死信 queue.
您知道在订阅者重新连接之前保留消息的方法吗?
附录 1:STOMP 消息
我正在使用 Stomp.Net Library with SelectorsCore Example 但仅减少到选择器 s1。工作流程和我上面写的有点不同。
不幸的是,我没有找到启用将 STOMP 消息记录到 Artemis 文件中的示例。因此,我用 WireShark, exported as text and uploaded into Gist StompMessages.txt 记录了数据包。您可以在那里看到不同的 STOMP 消息,例如搜索 CONNECT、SEND 等
解决方案
解决方案是在 broker.xml
中的 acceptor
元素中使用选项 anycastPrefix=/queue/
强制 queue 键入 ANYCAST
:
<acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;anycastPrefix=/queue/</acceptor>
您观察到的是预期的行为。如果您将消息发送到没有队列的地址(或者在 STOMP 术语中 - 没有订阅者的目的地),那么该消息将无处可去并被丢弃。这是正常的 pub/sub 语义。
如果您想在没有订阅者的情况下保留消息,您可以:
- 使用任播(即点对点)语义而不是多播。 Artemis documentation.
中对此进行了讨论
- 使用 "durable" STOMP 订阅者,如 Artemis documentation 中所述。这里需要注意的是,在发送消息之前仍然需要创建订阅,并且您还需要确保在完成订阅后删除订阅,否则它可能会累积消息。
我只使用 Artemis 2.6.2
和 STOMP 以及以下星座:
经纪人:
- 在 broker.xml 中没有配置 queue,一切都是自动创建的。
服务器:
- 订阅目的地
TaskResponse
没有 selector/filter - 使用 header clientId = ID(服务器请求的客户端 ID)发送到目的地
TaskRequest
客户端 123:
- 使用选择器 clientId = 123 订阅目的地
- 使用 header clientId = 123 发送到目的地
TaskRequest
TaskResponse
当我在 Artemis Console
观看时,会发生以下情况:
没有连接服务器和客户端:没有地址或 queue 存在
服务器连接:
Artemis
创建多播地址TaskResponse
并为此地址创建多播 queue,过滤器为空客户端 123 连接:
Artemis
创建多播地址TaskRequest
并为此地址创建多播 queue,过滤器 clientId = 123消息交换:消息按预期从服务器传输到客户端并返回服务器。
客户端 123 断开连接:
Artemis
删除多播地址TaskRequest
和对应的多播 queue,过滤器 clientId = 123服务器向客户端 123 的 TaskRequest 发送消息:根据服务器上的
STOMP
客户端消息发送成功。在代理上,消息消失了。反之亦然:客户端 123 已连接,服务器未连接:根据客户端 123 上的
STOMP
客户端,消息发送成功。在代理上,消息消失了。
我的猜测是消息被丢弃是因为没有到订阅者的路由。如果我在 broker.xml 的 address-settings 部分启用选项 "send-to-dla-on-no-route",消息将直接转到死信 queue.
您知道在订阅者重新连接之前保留消息的方法吗?
附录 1:STOMP 消息
我正在使用 Stomp.Net Library with SelectorsCore Example 但仅减少到选择器 s1。工作流程和我上面写的有点不同。
不幸的是,我没有找到启用将 STOMP 消息记录到 Artemis 文件中的示例。因此,我用 WireShark, exported as text and uploaded into Gist StompMessages.txt 记录了数据包。您可以在那里看到不同的 STOMP 消息,例如搜索 CONNECT、SEND 等
解决方案
解决方案是在 broker.xml
中的 acceptor
元素中使用选项 anycastPrefix=/queue/
强制 queue 键入 ANYCAST
:
<acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;anycastPrefix=/queue/</acceptor>
您观察到的是预期的行为。如果您将消息发送到没有队列的地址(或者在 STOMP 术语中 - 没有订阅者的目的地),那么该消息将无处可去并被丢弃。这是正常的 pub/sub 语义。
如果您想在没有订阅者的情况下保留消息,您可以:
- 使用任播(即点对点)语义而不是多播。 Artemis documentation. 中对此进行了讨论
- 使用 "durable" STOMP 订阅者,如 Artemis documentation 中所述。这里需要注意的是,在发送消息之前仍然需要创建订阅,并且您还需要确保在完成订阅后删除订阅,否则它可能会累积消息。