问题描述

Service Bus如何确保消息发送成功,发送端是否有Ack机制(是否有回调API告诉发送端,服务端已经收到消息)?根据对.NET发送Service Bus消息代码的分析,发送方法queueClient.SendAsync(message)并没有返回值,所以无法知道发送消息是否成功。

【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制_筛选器

 

 

问题根源

Azure 服务总线已针对持久性进行优化,会确保在服务确认请求成功之前,发送到服务总线的所有数据将提交到存储。一旦服务总线成功“ACK”(确认)请求,即表示服务总线已成功处理该请求。 如果服务总线返回“NACK”(失败),则表示服务总线无法处理该请求,客户端应用程序必须重试该请求。官方提供的SDK,在没有自定义RetryPolicy的情况下,都会采用默认的重试机制。

 

Service Bus .Net SDK 默认的重试机制(RetryPolicy)为:

  • DeltaBackoff: 重试之间的间隔时间
  • MaxRetryCount: 最大重试次数
  • MaximumBackoff: 最大的间隔时间
  • MinimalBackoff: 最小的间隔时间

【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制_Service Bus_02

 

所以在调用Service Bus SDK发送消息时,如果代码正常执行且没有Exception,则表示消息成功发送。

【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制_客户端_03

 

一句话总结为:无错即成功,失败看异常。

 

另外也有如下两种发送俩查看消息:

方式一:在Azure Service Bus门户中查看指标 Incoming request/message

【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制_筛选器_04

 

 

方式二:通过​​Servie Bus Explorer​​工具查看发送消息的内容

【Azure Service Bus】 Service Bus如何确保消息发送成功,发送端是否有Ack机制_microsoft_05

 

Service Bus异常消息类型

  1. 用户代码错误(​​System.ArgumentException​​​、​​System.InvalidOperationException​​​、​​System.OperationCanceledException​​​、​​System.Runtime.Serialization.SerializationException​​)。 常规操作:继续之前尝试修复代码。
  2. 设置/配置错误(​​Microsoft.ServiceBus.Messaging.MessagingEntityNotFoundException​​​、​​System.UnauthorizedAccessException​​)。 常规操作:检查配置,必要时进行更改。
  3. 暂时性异常(​​Microsoft.ServiceBus.Messaging.MessagingException​​​、​​Microsoft.ServiceBus.Messaging.ServerBusyException​​​、​​Microsoft.ServiceBus.Messaging.MessagingCommunicationException​​​)。 常规操作:重试操作或通知用户。 客户端 SDK 中的​​RetryPolicy​​​ 类可以配置为自动处理重试。 有关详细信息,请参阅​​重试指南​​。
  4. 其他异常(​​System.Transactions.TransactionException​​​、​​System.TimeoutException​​​、​​Microsoft.ServiceBus.Messaging.MessageLockLostException​​​、​​Microsoft.ServiceBus.Messaging.SessionLockLostException​​)。 常规操作:特定于异常类型。

 

异常类型

下表列出了消息异常的类型及其原因,并说明可以采取的建议性操作。

异常类型 异常类型说明/原因/示例建议的操作自动/立即重试注意事项​​TimeoutException​​服务器在 ​​OperationTimeout​​ 控制的指定时间内未响应请求的操作。 服务器可能已完成请求的操作。 这可能是由于网络或其他基础结构延迟造成的。检查系统状态的一致性,并根据需要重试。 请参阅​​超时异常​​。在某些情况下,重试可能会有帮助;在代码中添加重试逻辑。​​InvalidOperationException​​不允许在服务器或服务中执行请求的用户操作。 有关详细信息,请查看异常消息。 例如,如果在 ​​ReceiveAndDelete​​ 模式下收到消息,则 ​​Complete()​​ 将生成此异常。检查代码和文档。 确保请求的操作有效。重试不起作用。​​OperationCanceledException​​尝试对已关闭、中止或释放的对象调用某个操作。 在极少数情况下,环境事务已释放。检查代码并确保代码不会对已释放的对象调用操作。重试不起作用。​​UnauthorizedAccessException​​​​TokenProvider​​ 对象无法获取令牌,该令牌无效,或者令牌不包含执行操作所需的声明。确保使用正确的值创建令牌提供程序。 检查访问控制服务的配置。在某些情况下,重试可能会有帮助;在代码中添加重试逻辑。​​ArgumentException​​​​ArgumentNullException​​​​ArgumentOutOfRangeException​​提供给该方法的一个或多个参数均无效。
提供给 ​​NamespaceManager​​ 或 ​​Create​​ 的 URI 包含路径段。
提供给 ​​NamespaceManager​​ 或 ​​Create​​ 的 URI 方案无效。
属性值大于 32 KB。检查调用代码并确保参数正确。重试不起作用。​​MessagingEntityNotFoundException​​与操作关联的实体不存在或已被删除。确保该实体存在。重试不起作用。​​MessageNotFoundException​​尝试接收具有特定序列号的消息。 找不到此消息。确保该消息尚未接收。 检查死信队列,以确定该消息是否被视为死信。重试不起作用。​​MessagingCommunicationException​​客户端无法与服务总线建立连接。确保提供的主机名正确并且主机可访问。

如果你的代码在使用防火墙/代理的环境中运行,请确保到服务总线域/IP 地址和端口的流量未被阻止。

如果存在间歇性的连接问题,重试可能会有帮助。​​ServerBusyException​​服务目前无法处理请求。客户端可以等待一段时间,并重试操作。客户端可在特定的时间间隔后重试操作。 如果重试导致其他异常,请检查该异常的重试行为。​​MessagingException​​在以下情况下,可能会引发一般消息异常:

尝试使用属于其他实体类型(例如主题)的名称或路径创建 ​​QueueClient​​。

尝试发送大于 256 KB 的消息。

服务器或服务在处理请求期间遇到错误。 有关详细信息,请查看异常消息。 这通常是暂时性异常。

 

由于实体正受到限制,因此已终止请求。 错误代码:50001、50002、50008。

检查代码,并确保只对消息正文使用可序列化对象(或使用自定义序列化程序)。

在文档中查看属性支持的值类型,并只使用支持的类型。

检查 ​​IsTransient​​ 属性。 如果为 true,可以重试操作。

如果异常是由于限制导致的,请等待几秒钟,然后重试该操作。 重试行为未定义,在其他场景中可能没有帮助。​​MessagingEntityAlreadyExistsException​​尝试使用已被该服务命名空间中另一实体使用的名称创建实体。删除现有的实体,或者选择不同的名称来创建实体。重试不起作用。​​QuotaExceededException​​消息实体已达到其允许的最大大小,或已超出到命名空间的最大连接数。通过从实体或其子队列接收消息在该实体中创建空间。 请参阅​​QuotaExceededException​​。如果同时已删除消息,则重试可能会有帮助。​​RuleActionException​​如果尝试创建无效的规则操作,服务总线将返回此异常。 如果在处理该消息的规则操作时出错,服务总线会将此异常附加到死信消息。检查规则操作是否正确。重试不起作用。​​FilterException​​如果尝试创建无效的筛选器,服务总线将返回此异常。 如果在处理该消息的筛选器时出错,服务总线会将此异常附加到死信消息。检查筛选器是否正确。重试不起作用。​​SessionCannotBeLockedException​​尝试接受具有特定会话 ID 的会话,但该会话当前已被另一客户端锁定。确保该会话未由其他客户端锁定。如果在此期间会话已释放,则重试可能会有帮助。​​TransactionSizeExceededException​​事务包含过多的操作。减少此事务中操作的数目。重试不起作用。​​MessagingEntityDisabledException​​对已禁用的实体请求运行时操作。激活实体。如果在此期间该实体已激活,则重试可能会有帮助。​​NoMatchingSubscriptionException​​如果向已启用预筛选的主题发送消息并且所有筛选器都不匹配,则服务总线返回此异常。确保至少有一个筛选器匹配。重试不起作用。​​MessageSizeExceededException​​消息有效负载超出 256 KB 限制。 256-KB 限制是指总消息大小,可能包括系统属性和任何 .NET 开销。减少消息负载的大小,并重试操作。重试不起作用。​​TransactionException​​环境事务 (Transaction.Current) 无效。 该事务可能已完成或已中止。 内部异常可能提供了更多信息。 重试不起作用。​​TransactionInDoubtException​​已对未决事务尝试进行操作,或尝试提交该事务并且事务进入不确定状态。应用程序必须处理此异常(作为特例),因为此事务可能已提交。

参考资料

Service Bus Explorer:​https://github.com/paolosalvatori/ServiceBusExplorer/releases​

Service Bus Retry Policy:​https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#service-bus​

 

当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!