消息可能无法成功投递(例如,使用事务会话在进行消息消费时被回滚)。这样的消息回到其队列准备重新传递。 但是,这意味着在不会成功的情况下可以一次又一次地传递消息,从而无限期地保留在队列中,导致堵塞系统。
有两种方法可以处理这些未投递的消息:
- 延迟重新投递:可以延迟消息的重新投递。 这使客户端有时间从任何瞬态故障中恢复,并防止其网络或CPU资源过载。
- 死信地址:也可以配置一个死信地址,以便在指定次数的不成功投递后,从队列中删除消息并将其发送到死信地址。 这些消息将不会再从此队列中投递。
延迟重新投递
在客户端经常出现故障或回滚的情况下,延迟重新投递通常很有用。 如果没有延迟重新投递,系统可能会进入“超负荷”状态,尝试投递,客户端回滚,并且无限期地重新尝试投递,消耗宝贵的CPU和网络资源。
配置延迟重新投递例子如下:
<!-- delay redelivery of messages for 5s -->
<address-setting match="exampleQueue">
<!-- default is 1.0 -->
<redelivery-delay-multiplier>1.5</redelivery-delay-multiplier>
<!-- default is 0 (no delay) -->
<redelivery-delay>5000</redelivery-delay>
<!-- default is redelivery-delay * 10 -->
<max-redelivery-delay>50000</max-redelivery-delay>
</address-setting>
如果指定了延迟重新投递,Artemis将在重新投递消息之前等待此延迟时间。默认情况下,没有重新传递延迟(redelivery-delay设置为0)。其他后续消息将有规律的发送,只有取消的消息将在延迟后异步发送回队列。
可以设定在redelivery-delay上延迟倍数(redelivery-delay-multiplier)。 每次重新传递消息时,延迟时间将等于上一个延迟乘以redelivery-delay-multiplier的值。 可以设置max-redelivery-delay以防止延迟时间变得太大。max-redelivery-delay默认值为redelivery-delay*10。例如:
- redelivery-delay=5000, redelivery-delay-multiplier=2, max-redelivery-delay=15000
1. Delivery Attempt 1. (Unsuccessful)
2. Wait Delay Period: 5000
3. Delivery Attempt 2. (Unsuccessful)
4. Wait Delay Period: 10000 // (5000 * 2) < max-delay-period. Use 10000
5. Delivery Attempt 3: (Unsuccessful)
6. Wait Delay Period: 15000 // (10000 * 2) > max-delay-period: Use max-delay-delivery
死信地址
为了防止客户端无限地接收相同的未投递成功的消息(无论何原因导致传递失败),消息传递系统定义死信地址:在指定的不成功投递尝试次数之后,消息将从其队列中删除并发送到死信地址。可以将任何此类消息转移到队列,系统管理员稍后可以将这些消息用于队列以采取某些行动。
Artemis的地址可以分配一个死信地址。 一旦消息在给定次数的尝试中未成功投递,它们将从队列中删除并发送到相关的死信地址。 这些死信消息以后可以从死信地址中消费,以便进一步检查。
死信地址配置例子如下:
<!-- undelivered messages in exampleQueue will be sent to the dead letter address
deadLetterQueue after 3 unsuccessful delivery attempts -->
<address-setting match="exampleQueue">
<dead-letter-address>deadLetterQueue</dead-letter-address>
<max-delivery-attempts>3</max-delivery-attempts>
</address-setting>
如果没有配置死信地址,将在重新投递max-delivery-attempts设定的次数后丢弃消息。默认情况下,消息最多重新投递10次。 将max-delivery-attempts设置为-1以获得无限重新投递次数。
从死信地址中消费的死信消息具有如下属性值:
- _AMQ_ORIG_ADDRESS:字符串属性,包含死信消息的原始地址信息。
- _AMQ_ORIG_QUEUE:字符串属性,包含死信消息的原始队列信息。
投递计数持久化
在正常使用中,Artemis不会持续更新投递计数持久化,直到回滚消息(即在将消息投递给消费者之前未更新投递计数)。在大多数消息投递用例中,消息一被消费,就会被确认和遗忘。在这些情况下,在传递消息之前更新投递计数持久化将为每个投递的消息添加额外的持久化步骤,这意味着显着的性能损失。
但是,如果在消息投递发生之前未进行更新传递计数持久化,则在服务器崩溃的情况下,消息可能已投递但不会反映在传递计数中。在恢复阶段,服务器将不知道这一点,并且会将redelivered设置为false的消息重新投递。由于此行为会破坏严格的JMS定义,因此 Artemis允许在消息投递之前存储投递计数,但由于性能影响,默认情况下会禁用此功能。为了开启此功能可以将persist-delivery-count-before-delivery设置为true,例子如下:
<persist-delivery-count-before-delivery>true</persist-delivery-count-before-delivery>
注:此系列文章为Apache Artemis V2.6.2官方使用文档的简要翻译文档(非完全按照官方文档排版进行翻译,有删减),个人能力有限如有错误请谅解。源文档地址:http://activemq.apache.org/artemis/docs/latest/index.html