Azure 服务总线故障排除指南
本文提供的故障排除技巧和建议适用于你在使用 Azure 服务总线时看到的一些问题。
连接问题
连接到服务时超时
根据主机环境和网络,连接问题可能会以 TimeoutException
、OperationCanceledException
或者 Reason
为 ServiceTimeout
的 ServiceBusException
的形式呈现给应用程序,并且大多数情况下,当客户端找不到服务的网络路径时,通常会发生。
故障排除:
- 验证创建客户端时指定的连接字符串或完全限定的域名是否正确。 有关如何获取连接字符串的信息,请参阅获取服务总线连接字符串。
- 检查托管环境中的防火墙和端口权限。 检查高级消息队列协议 (AMQP) 端口 5671 和 5672 是否已开放,以及是否允许通过防火墙访问终结点。
- 请尝试使用 Web 套接字传输选项,该选项使用端口 443 进行连接。 有关详细信息,请参阅配置传输。
- 查看网络是否阻止了特定 IP 地址。 有关详细信息,请参阅需要允许哪些 IP 地址?
- 如果适用,请验证代理配置。 有关详细信息,请参阅:配置传输
- 有关排查网络连接问题的详细信息,请参阅:[连接性、证书或超时问题][#connectivity-certificate-or-timeout-issues]。
安全套接字层 (SSL) 握手失败
使用拦截代理时,可能会出现此错误。 若要验证,建议在禁用代理的主机环境中测试应用程序。
套接字耗尽错误
应用程序应优先将 Microsoft Azure 服务总线类型视为单一实例,并在应用程序的生存期内创建和使用单个实例。 创建的每个新 ServiceBusClient 将产生使用套接字的新 AMQP 连接。 ServiceBusClient 类型管理从该实例创建的所有类型的连接。 每个 ServiceBusReceiver、ServiceBusSessionReceiver、ServiceBusSender 以及 ServiceBusProcessor 为相关联的 Microsoft Azure 服务总线实体管理其自己的 AMQP 链接。 使用 ServiceBusSessionProcessor 时,会根据并发处理的会话数建立多个 AMQP 链接。
客户端在空闲时可以安全地缓存;它们将确保有效管理网络、CPU 和内存使用,最大限度地减少它们在不活动期间的影响。 此外,当不再需要客户端时,必须调用 CloseAsync
或 DisposeAsync
,以确保正确清理网络资源。
将组件添加到连接字符串不起作用
Microsoft Azure 服务总线客户端库的当前代系仅支持 Microsoft Azure 门户发布的形式的连接字符串。 连接字符串仅用于提供基本位置和共享密钥信息。 客户端的配置行为是通过其选项完成的。
以前几代的 Microsoft Azure 服务总线客户端允许通过将键/值组件添加到连接字符串来配置某些行为。 这些组件不再被识别,对客户端行为没有影响。
“TransportType=AmqpWebSockets”替代项
若要将 Web 套接字配置为传输类型,请参阅配置传输。
“Authentication=Managed Identity”替代项
若要使用托管标识进行身份验证,请参阅:标识和共享访问凭据。 有关 Azure.Identity
库的详细信息,请参阅身份验证和 Azure SDK。
日志记录和诊断
Microsoft Azure 服务总线客户端库通过使用 .NET EventSource
发出信息,完全检测了各种详细级别的日志记录信息。 对每个操作执行日志记录,并遵循标记操作起点、其操作和遇到的任何异常的模式。 可能提供见解的其他信息也会记录在关联操作的上下文中。
启用日志记录
Microsoft Azure 服务总线客户端日志可用于任何 EventListener
,方法是选择加入从 Azure-Messaging-ServiceBus
开始的源,或选择加入所有具有特征 AzureEventSource
的源。 为了更轻松地从 Microsoft 客户端库捕获日志,服务总线使用的 Azure.Core
库提供了一个 AzureEventSourceListener
。
有关详细信息,请参阅:使用 Azure SDK for .NET 进行日志记录。
分布式跟踪
Microsoft Azure 服务总线客户端库通过与 Application Insights SDK 集成来支持分布式跟踪。 它还通过 .NET 5 中引入的 .NET ActivitySource 类型对 OpenTelemetry 规范提供了试验性支持。 若要启用 ActivitySource
支持以与 OpenTelemetry 一起使用,请参阅 ActivitySource 支持。
若要使用 GA DiagnosticActivity 支持,可以与 Application Insights SDK 集成。 有关更多详细信息,请参阅将 ApplicationInsights 与 Azure Monitor 配合使用。
该库会创建以下跨度:
Message
ServiceBusSender.Send
ServiceBusSender.Schedule
ServiceBusSender.Cancel
ServiceBusReceiver.Receive
ServiceBusReceiver.ReceiveDeferred
ServiceBusReceiver.Peek
ServiceBusReceiver.Abandon
ServiceBusReceiver.Complete
ServiceBusReceiver.DeadLetter
ServiceBusReceiver.Defer
ServiceBusReceiver.RenewMessageLock
ServiceBusSessionReceiver.RenewSessionLock
ServiceBusSessionReceiver.GetSessionState
ServiceBusSessionReceiver.SetSessionState
ServiceBusProcessor.ProcessMessage
ServiceBusSessionProcessor.ProcessSessionMessage
ServiceBusRuleManager.CreateRule
ServiceBusRuleManager.DeleteRule
ServiceBusRuleManager.GetRules
大多数跨度都是不言自明的,并且在以其名称命名的操作过程中启动和停止。 将其他对象关联在一起的跨度是 Message
。 跟踪消息的方式是通过在发送和计划操作期间由库在 ServiceBusMessage.ApplicationProperties 属性中设置的 Diagnostic-Id
。 在 Application Insights 中,Message
跨度显示为链接到用于与消息进行交互的各种其他跨度,例如,ServiceBusReceiver.Receive
跨度、ServiceBusSender.Send
跨度和 ServiceBusReceiver.Complete
跨度都将从 Message
跨度链接。 下面是 Application Insights 中的一个示例:
在上面的屏幕截图中,可以看到可在门户中的 Application Insights 中查看的端到端事务。 在此方案中,应用程序正在发送消息并使用 ServiceBusSessionProcessor 来处理它们。 Message
活动链接到 ServiceBusSender.Send
、ServiceBusReceiver.Receive
、ServiceBusSessionProcessor.ProcessSessionMessage
和 ServiceBusReceiver.Complete
。
注意
有关详细信息,请参阅通过 Microsoft Azure 服务总线消息传递进行分布式跟踪和关联。
排查发送方问题
无法发送具有多个分区键的批次
当应用将一个批次发送到启用了分区的实体时,单个发送操作中包含的所有消息必须具有相同的 PartitionKey
。 如果实体已启用会话,则 SessionId
属性的要求相同。 若要发送具有不同 PartitionKey
或 SessionId
值的消息,请将消息分组在单独的 ServiceBusMessageBatch
实例中,或将它们包含在对 SendMessagesAsync 重载(采用一组 ServiceBusMessage
实例)的单独调用中。
批次无法发送
一个消息批次是包含两条或多条消息的 ServiceBusMessageBatch
,或者是对 SendMessagesAsync 的调用(其中传入两条或更多消息)。 该服务不允许一个消息批次超过 1 MB。 无论是否启用“高级大型消息支持”功能,此行为都是如此。 如果想要发送大于 1 MB 的消息,则必须单独发送它,而不是与其他消息分组发送。 遗憾的是,ServiceBusMessageBatch 类型目前不支持验证某个批次是否包含任何大于 1MB 的消息,因为大小受服务限制,这可能会更改。 因此,如果打算使用高级大型消息支持功能,请确保单独发送超过 1 MB 的消息。
排查接收方问题
返回的消息数与批量接收中请求的数量不匹配
当尝试执行批量接收操作时,也就是说,将 maxMessages
值 2 或更大值传递给 ReceiveMessagesAsync 方法时,即使队列或订阅当时有许多可用消息,并且即使整个配置的 maxWaitTime
尚未过期,也不能保证接收到请求的消息数。 为了最大限度地提高吞吐量并避免锁定过期,一旦第一条消息传来,接收方会先额外等待 20 毫秒以等待任何其他消息,然后调度消息进行处理。 maxWaitTime
控制接收方等待接收第一条消息的时长 - 随后的消息会等待 20 毫秒。 因此,应用程序不应假定所有可用的消息都会在一次调用中接收。
消息或会话锁定在锁定到期时间之前丢失
服务总线服务使用 AMQP 协议,该协议是有状态的。 由于协议的性质,如果连接客户端和服务的链路在接收消息后但在消息解决之前拆离,则无法在重新连接链路时解决该消息。 由于短期暂时性网络故障、网络中断或服务强制实施 10 分钟空闲超时,可以拆离链接。 链接重新连接会作为任何需要链接的操作(即解决或接收消息)的一部分自动进行。 在这种情况下,即使锁定到期时间尚未过去,你也会收到 Reason
为 MessageLockLost
或 SessionLockLost
的 ServiceBusException
。
如何浏览计划消息或延迟消息
速览消息时,将包括计划消息和延迟消息。 它们可以通过 ServiceBusReceivedMessage.State 属性来标识。 获得延迟消息的 SequenceNumber 后,可以通过 ReceiveDeferredMessagesAsync 方法利用锁定接收它。
在处理主题时,无法速览订阅上的计划消息,因为这些消息一直保留在主题中,直到计划的排队时间。 解决方法是,可以构造 ServiceBusReceiver 传入主题名称,以便速览此类消息。 使用主题名称时,接收方的其他操作将不起作用。
如何浏览所有会话中的会话消息
可以使用常规 ServiceBusReceiver 速览所有会话。 若要查看特定会话,可以使用 ServiceBusSessionReceiver,但需要获取会话锁定。
访问消息正文时引发 NotSupportedException
当收到从使用不同 AMQP 消息正文格式的不同库发送的消息时,通常会在互操作方案中出现此问题。 如果要与这些类型的消息交互,请参阅 AMQP 消息正文示例以了解如何访问消息正文。
解决处理器问题
自动锁定续订不起作用
自动锁定续订依赖于系统时间来确定何时续订消息或会话的锁定。 如果系统时间不准确,例如,时钟速度缓慢,则可能不会在锁定丢失之前发生锁定续订。 如果自动锁定续订不起作用,请确保系统时间准确。
使用高并发时,处理器似乎挂起或出现延迟问题
这行为通常是由线程饥饿引起的,尤其是在使用会话处理器和使用相对于机器上的核心数量非常高的 MaxConcurrentSessions 值时。 首先检查的是确保未在任何事件处理程序中执行异步中同步。 异步中同步是导致死锁和线程饥饿的一种简单方法。 即使未执行异步中同步,处理程序中的任何纯同步代码都可能导致线程饥饿。 如果确定这不是问题,例如,因为只有纯异步代码,则可以尝试增加 [TryTimeout][TryTimeout]。 它会通过减少在使用会话处理器时发生的上下文切换数量和超时来减轻线程池的压力。 [TryTimeout][TryTimeout] 的默认值为 60 秒,但最多可设置为 1 小时。 我们建议以 TryTimeout
设置为 5 分钟作为测试起点,并从那里开始迭代。 如果上述任何建议都不起作用,则只需横向扩展到多个主机,减少应用程序中的并发性,但在多个主机上运行应用程序以实现所需的整体并发。
延伸阅读:
会话处理器切换会话的时间过长
这可以使用 [SessionIdleTimeout][SessionIdleTimeout] 进行配置,该参数告诉处理器在放弃并转移到另一个会话之前等待从会话接收消息的时间。 如果有许多稀疏填充的会话,其中每个会话只有一些消息,则会非常有用。 如果预计每个会话将产生许多消息,则设置太低可能会适得其反,因为这会导致不必要的会话关闭。
处理器立即停止
对于演示或测试方案,通常会观察到这种情况。 StartProcessingAsync
在处理器启动后立即返回。 调用此方法不会阻止应用程序,并在处理器运行时使应用程序保持活动状态,因此需要其他一些机制才能执行此操作。 对于演示或测试,只需在启动处理器后添加 Console.ReadKey()
调用就足够了。 对于生产方案,你可能希望使用某种框架集成(如 [BackgroundService][BackgroundService])来提供方便的应用程序生命周期挂钩,其可用于启动和释放处理器。
排查事务问题
有关 Microsoft Azure 服务总线中的事务的一般信息,请参阅 [服务总线事务处理概述][事务]。
支持的操作
使用事务时,并非所有操作都受支持。 若要查看支持的事务列表,请参阅 [事务范围内的操作][TransactionOperations]。
Timeout
事务在 [时间段][TransactionTimeout] 之后超时,因此,事务范围内发生的处理必须遵循此超时。
不会重试事务中的操作
这是设计的结果。 请考虑以下场景 - 你试图在事务中完成消息,但出现了一些暂时错误,例如 Reason
为 ServiceCommunicationProblem
的 ServiceBusException
。 假设请求确实到达了服务。 如果客户端重试,该服务将看到两次完成请求。 在提交事务之前,不会最终确定第一次完成。 第二次完成甚至无法在第一次完成结束之前进行评估。 客户端上的事务正在等待该次完成结束。 这会创建一个死锁,其中服务正在等待客户端完成事务,但客户端正在等待服务确认第二次完成操作。 该事务最终会在 2 分钟后超时,但这是一种糟糕的用户体验。 因此,我们不会在事务中重试操作。
跨实体的事务不起作用
若要执行涉及多个实体的事务,需要将 ServiceBusClientOptions.EnableCrossEntityTransactions
属性设置为 true
。 有关详细信息,请参阅 [跨实体的事务][CrossEntityTransactions] 示例。
配额
可在 [此处][ServiceBusQuotas] 找到有关 Microsoft Azure 服务总线配额的信息。
连接性、证书或超时问题
以下步骤可帮助排查 *.servicebus.chinacloudapi.cn 下所有服务的连接性/证书/超时问题。
浏览到
https://<yournamespace>.servicebus.chinacloudapi.cn/
或对其运行 wget。 这可帮助检查是否存在 IP 筛选或虚拟网络或证书链问题(在使用 Java SDK 时常见)。成功消息的示例:
<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Publicly Listed Services</title><subtitle type="text">This is the list of publicly-listed services currently available.</subtitle><id>uuid:27fcd1e2-3a99-44b1-8f1e-3e92b52f0171;id=30</id><updated>2019-12-27T13:11:47Z</updated><generator>Service Bus 1.1</generator></feed>
失败错误消息的示例:
<Error> <Code>400</Code> <Detail> Bad Request. To know more visit https://aka.ms/sbResourceMgrExceptions. . TrackingId:b786d4d1-cbaf-47a8-a3d1-be689cda2a98_G22, SystemTracker:NoSystemTracker, Timestamp:2019-12-27T13:12:40 </Detail> </Error>
运行以下命令,检查防火墙是否阻止了任何端口。 所用的端口为 443 (HTTPS)、5671 和 5672 (AMQP) 和 9354 (Net Messaging/SBMP)。 根据使用的库,还会使用其他端口。 下面是用于检查是否阻止了 5671 端口的示例命令。 C
tnc <yournamespacename>.servicebus.chinacloudapi.cn -port 5671
在 Linux 上:
telnet <yournamespacename>.servicebus.chinacloudapi.cn 5671
出现间歇性连接问题时,请运行以下命令,检查是否存在任何丢弃的数据包。 此命令尝试每 1 秒与服务建立 25 个不同的 TCP 连接。 然后,可以检查其中有多少成功/失败,还可以查看 TCP 连接延迟。 可以从
psping
下载psping
工具。.\psping.exe -n 25 -i 1 -q <yournamespace>.servicebus.chinacloudapi.cn:5671 -nobanner
如果使用的是其他工具(如
tnc
、ping
等),则可以使用等效的命令。如果上述步骤没有帮助,请获取网络跟踪,并使用 Wireshark 之类的工具对其进行分析。 如果需要,请联系 Azure 支持部门。
若要查找要添加到连接允许列表的正确 IP 地址,请参阅我需要添加到允许列表的 IP 地址。
注意
2026 年 9 月 30 日,我们将不再支持 Azure 服务总线的 SBMP 协议,因此在 2026 年 9 月 30 日之后,你将无法再使用此协议。 请在该日期之前迁移到最新的使用 AMQP 协议的 Azure 服务总线 SDK 库,新库提供了关键安全更新和改进功能。
有关详细信息,请参阅支持停用公告。
服务升级/重启时可能出现的问题
症状
- 请求可能会暂时受到限制。
- 传入的消息/请求可能会减少。
- 日志文件可能包含错误消息。
- 应用程序可能会与服务断开连接几秒钟。
原因
后端服务升级和重启可能会在应用程序中导致这些问题。
解决
如果应用程序代码使用 SDK,则重试策略已内置且处于活动状态。 应用程序会重新连接,此操作不会对应用程序/工作流产生重大影响。
未授权访问:需要发送声明
现象
尝试使用具有发送权限的用户分配的托管标识从本地计算机上的 Visual Studio 访问 Microsoft Azure 服务总线主题时,可能会出现此错误。
Service Bus Error: Unauthorized access. 'Send' claim\(s\) are required to perform this operation.
原因
标识无权访问服务总线主题。
解决方法
要解决此错误,请安装 Microsoft.Azure.Services.AppAuthentication 库。 有关详细信息,请参阅本地开发身份验证。
要了解如何将权限分配给角色,请参阅使用 Microsoft Entra ID 对托管标识进行身份验证,以便访问 Azure 服务总线资源。
服务总线异常:put-token 失败
症状
看到以下错误消息:
Microsoft.Azure.ServiceBus.ServiceBusException: Put token failed. status-code: 403, status-description: The maximum number of '1000' tokens per connection has been reached.
注意
2026 年 9 月 30 日,我们将停用 Azure 服务总线 SDK 库 WindowsAzure.ServiceBus、Microsoft.Azure.ServiceBus 和 com.microsoft.azure.servicebus,这些库不符合 Azure SDK 准则。 我们还将结束对 SBMP 协议的支持,因此在 2026 年 9 月 30 日之后,你将无法再使用此协议。 请在该日期之前迁移到最新的 Azure SDK 库,新库提供了关键安全更新和改进功能。
尽管旧库在 2026 年 9 月 30 日之后仍可使用,但它们将不再获得 Azure 的官方支持和更新。 有关详细信息,请参阅支持停用公告。
原因
与服务总线命名空间的单个连接中的并发链接的身份验证令牌数已超过限制:1000。
解决方法
执行以下步骤中的一个:
- 减少单个连接中的并发链接数或使用新连接
- 将 SDK 用于 Azure 服务总线,这可确保不会遇到这种情况(推荐)
使用数据平面 SDK 时,资源锁不起作用
症状
你已在服务总线命名空间上配置了删除锁,但能够使用服务总线资源管理器删除命名空间中的资源(队列、主题,等等)。
原因
资源锁保留在 Azure 资源管理器(控制平面)中,它不会阻止数据平面 SDK 调用直接从命名空间中删除资源。 独立的服务总线资源管理器使用数据平面 SDK,因此可以进行删除。
解决方法
建议通过 Azure 门户、PowerShell、CLI 或 资源管理器模板使用基于 Azure 资源管理器的 API 来删除实体,以便资源锁可防止意外删除资源。
实体不再可用
症状
你看到一条错误,指出该实体不再可用。
原因
资源可能已被删除。 请按照以下步骤确定实体被删除的原因。
- 检查活动日志以查看是否存在 Azure 资源管理器删除请求。
- 检查操作日志以查看是否有用于删除的直接 API 调用。 若要了解如何收集运行日志,请参阅监视 Azure 服务总线。 有关操作日志的架构和示例,请参阅操作日志
- 检查操作日志以查看是否存在
autodeleteonidle
相关删除。
后续步骤
请参阅以下文章:
- Azure 资源管理器异常。 这篇文章列出了使用 Azure 资源管理器(通过模板或直接调用)与 Azure 服务总线进行交互时生成的异常。
- 消息传送异常。 这篇文章列出了 Azure 服务总线的 .NET Framework 生成的异常。