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 中查看消息。 在以下示例中, 服务总线资源管理器 显示订阅的 DLQ 中当前有 62 条消息:test1。
还可以通过使用 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。 无法禁止此行为,但可将最大传送数设置为较大的数。
处理订阅规则时的错误
如果您在筛选器评估异常时启用死信队列,则在执行订阅的 SQL 筛选器规则时出现的任何错误以及出错的消息都会被捕获到 DLQ 中。 不要在包含发送到主题(没有订阅者)的消息类型的生产环境中使用此选项,因为它可能会产生大量 DLQ 消息负载。 因此,请确保发送到主题的所有消息至少具有一个匹配的订阅。
应用程序级死信
除了系统提供的死信功能外,应用程序也可以使用 DLQ 显式拒绝无法接受的消息。 这可能包括因系统问题而无法正确处理的消息、载有格式错误负载的消息,或在使用某种消息级安全方案时未通过身份验证的消息。
在 .NET 中,这可以通过调用 ServiceBusReceiver.DeadLetterMessageAsync method 来完成。
建议在DeadLetterReason中包含异常的类型,在DeadLetterDescription中包含异常的堆栈跟踪,因为这样可以更轻松地排查导致消息死信的问题原因。 这可能会导致某些消息超过 Azure 服务总线标准层的 256 KB 配额限制。 可以将服务总线命名空间从标准层升级到高级层以具有更高的配额和限制。
自动转发场景中的死信处理
在下列情况下,消息会发送到死信队列:
- 消息经过超过 4 个链接在一起的队列或主题。
- 目标队列或主题被禁用或删除。
- 目标队列或主题已超过最大实体大小。
通过发送途径场景中的死信处理
- 如果目标队列或主题被禁用,消息会被发送到源队列的传输死信队列(TDLQ)。
- 如果目标队列或目标实体超过其大小限制,消息将被发送到源队列的 TDLQ。
将死信消息发送以便重新处理
解决导致消息进入死信队列中的问题后,您可以将其重新提交到队列或主题以重新处理。 在某些情况下,如果死信队列中有许多消息需要移动,可以使用这样的代码来一次性移动所有消息。 操作员通常更喜欢使用用户界面,以便他们可以排查哪些消息类型处理失败、来自哪个源队列以及出于什么原因,同时还能够重新批量提交要重新处理的消息。
可用工具
- Azure 服务总线资源管理器支持在队列和主题之间手动移动消息。 它允许你查看消息列表并重新发送它们以重新处理。 无论使用何种 SDK 发送消息,都可通过 Azure 门户使用该服务。
- ServicePulse with NServiceBus 使用此集中式仪表板简化了错误处理流程。 快速可视化、分组、筛选和搜索错误,并有效地重试单个或分组的消息。 可用于 NServiceBus 终结点。
- ServicePulse with MassTransit 提供用于错误管理的集中式仪表板。 可以使用各种条件可视化、分组、筛选和搜索错误。 它还支持编辑和重试单个消息,或批处理重试消息组。 可用于 MassTransit 终结点。
相关内容
请参阅为队列或订阅启用死信,了解配置邮件到期时的死信设置的不同方式。