服务总线死信队列概述

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

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

死信队列

死信队列的用途是存放无法传递给任何接收方的消息或无法处理的消息。 然后,可从 DLQ 中删除和检查这些消息。 应用程序可能允许用户更正问题并重新提交消息。

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

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

死信队列的路径

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

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

在 .NET 中,可以使用方法 FormatDeadLetterPath

QueueClient.FormatDeadLetterPath(queuePath)
SubscriptionClient.FormatDeadLetterPath(topicPath, subscriptionName)

DLQ 消息计数

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

显示死信队列中的 62 条消息的图像。

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

将消息移到 DLQ

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

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

生存时间

在队列或订阅上启用死信时,所有过期的消息都将移动到 DLQ。 死信原因代码设置为:TTLExpiredException。 延迟消息在过期后不会被清除和移动到死信队列。 此行为是设计使然。

最大传送数

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

处理订阅规则时的错误

如果对筛选器评估异常启用死信,会在 DLQ 中捕获执行订阅的 SQL 筛选器规则时出现的任何错误以及有问题的消息。 不要在包含发送到主题(没有订阅者)的消息类型的生产环境中使用此选项,因为这可能会造成大量 DLQ 消息负载。 因此,请确保发送到主题的所有消息至少具有一个匹配的订阅。

应用程序级死信

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

在 .NET 中,这可以通过调用 ServiceBusReceiver.DeadLetterMessageAsync method 来完成。

建议在DeadLetterReason中包含异常的类型,在DeadLetterDescription中包含异常的堆栈跟踪,因为这样可以更轻松地排查导致消息死信的问题原因。 请注意,这可能会导致某些消息超过 Azure 服务总线标准层的 256 KB 配额限制。 可以将服务总线命名空间从标准层升级到高级层以具有更高的配额和限制

自动转发方案中的死信

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

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

通过方案发送中的死信

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

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

解决导致消息死信的问题后,可以将其重新提交到队列或主题以重新处理。

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

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