服务总线死信队列概述

Azure 服务总线队列和主题订阅提供一个名为“死信队列”(DLQ) 的辅助子队列。 死信队列不需要显式创建,并且不能删除或独立于主实体进行管理。

本文介绍服务总线中的死信队列。 GitHub 上的死信队列示例对很多讨论进行了说明。

死信队列

死信队列的用途是存放无法传递给任何接收方的消息或无法处理的消息。 然后,可从 DLQ 中删除和检查这些消息。 应用程序可能会在操作员的帮助下,更正问题并重新提交消息,记录出错的实际情况和执行更正操作。

从 API 和协议的角度看,DLQ 与任何其他队列都极其相似,不同的是,消息只能通过父实体的死信操作提交。 此外,无法查看生存时间,而且不能将 DLQ 中的消息设为死信。 死信队列完全支持扫视锁定传递和事务性操作。

DLQ 不会自动执行清理操作。 消息将保留在 DLQ 中,直到从 DLQ 中显式检索它们并完成死信消息为止。

DLQ 消息计数

无法在主题级别获取死信队列中的消息计数。 这是因为消息不会驻留在主题级别。 相反,当发送方将消息发送给主题时,消息会在毫秒内转发给主题的订阅,因此消息不再驻留于主题级别。 所以,你可以在与主题的订阅相关联的 DLQ 中查看消息。 在以下示例中,Service Bus Explorer 显示订阅“test1”的 DLQ 中目前有 62 条消息。

Image showing 62 messages in the dead-letter queue.

还可以通过使用 Azure CLI 命令:az servicebus topic subscription show 来获取 DLQ 消息的计数。

将消息移到 DLQ

服务总线中有几个活动会导致从消息引擎本身将消息推送到 DLQ。 应用程序也可以显式将消息移到 DLQ。 以下两个属性(死信原因和死信说明)将添加到死信消息中。 应用程序可以为死信原因属性定义其自己的代码,但系统会设置以下值。

死信原因 死信错误说明
HeaderSizeExceeded 已超过此流的大小配额。
TTLExpiredException 消息过期并已设为死信。 有关详细信息,请参阅生存时间部分。
会话 ID 为 null。 启用会话的实体不允许使用会话标识符为 null 的消息。
MaxTransferHopCountExceeded 超出了在队列之间转发时允许的最大跃点数。 此值设为 4。
MaxDeliveryCountExceeded 在最大传送尝试次数以后,仍然无法使用消息。 有关详细信息,请参阅最大传送数部分。

最大传送数

为服务总线队列和订阅传送消息的尝试次数是有限制的。 默认值为 10。 只要消息在 peek-lock 下传递,但已显式放弃或锁已过期,则消息的传送数就会递增。 如果传送数超出限制,会将消息移至 DLQ。 DLQ 中消息的死信原因设置为:MaxDeliveryCountExceeded。 无法禁止此行为,但可将最大传送数设置为较大的数。

生存时间

在队列或订阅上启用死信时,所有过期的消息都将移动到 DLQ。 死信原因代码设置为:TTLExpiredException

延迟消息在过期后不会被清除和移动到死信队列。 此行为是设计使然。

处理订阅规则时的错误

如果对筛选器评估异常启用死信,会在 DLQ 中捕获执行订阅的 SQL 筛选器规则时出现的任何错误以及有问题的消息。 请勿在部分消息类型没有订阅服务器的生产环境中使用此选项。

应用程序级死信

除了系统提供的死信功能外,应用程序也可以使用 DLQ 显式拒绝无法接受的消息。 这可能包括由于任何类型的系统问题而导致无法正确处理的消息、存储格式错误的有效负载的消息,或在使用某种消息级安全方案时未通过身份验证的消息。

这可以通过调用ServiceBusReceiver.DeadLetterMessageAsync 方法来完成。

建议在DeadLetterReason中包含异常的类型,在DeadLetterDescription中包含异常的堆栈跟踪,因为这样可以更轻松地排查导致消息死信的问题原因。 请注意,这可能会导致某些消息超过Azure 服务总线标准层的 256KB 配额限制,进一步指示应将高级层用于生产环境。

自动转发方案中的死信

在下列情况下,消息会发送到死信队列:

  • 消息传递 4 个以上链接在一起的队列或主题。
  • 目标队列或主题被禁用或删除。
  • 目标队列或主题超出最大实体大小。

通过方案发送中的死信

  • 如果目标队列或主题已禁用,会将消息发送到源队列的传输死信队列 (TDLQ)。
  • 如果删除目标队列或主题,会引发 404 异常。
  • 如果目标队列或实体超出实体大小,会将消息发送到源队列的 TDLQ。

死信队列的路径

可以通过使用以下语法来访问死信队列:

<queue path>/$deadletterqueue
<topic path>/Subscriptions/<subscription path>/$deadletterqueue

发送要重新处理的死信消息

由于最终出现在死信队列中的消息中可能包含有价值的业务数据,因此当操作员先处理好导致其变为死信消息的具体情况后,需要重新处理这些消息。

Azure 服务总线资源管理器等工具支持在队列和主题之间手动移动消息。 如果需要移动死信队列中的许多消息,可以借助这样的代码来一次性地移动它们。 操作员通常更喜欢使用用户界面,以便他们可以排查哪些消息类型处理失败、来自哪个源队列以及出于什么原因,同时还能够重新批量提交要重新处理的消息。 NServiceBus 和 ServicePulse 等工具可提供此类功能。

后续步骤

请参阅为队列或订阅启用死信,了解配置邮件到期时的死信设置的不同方式。