本文提供的故障排除技巧和建议适用于你在使用 Azure 服务总线时看到的一些问题。
资源健康状况
在 Azure 门户中服务总线命名空间的资源 运行状况 页上标记的不正常时间段可能比实际时间段长几分钟。 例如,页面可能指示命名空间在 5-6 分钟内运行不正常,而实际运行不正常的时间段仅为 1-2 分钟。
此行为是由于警报系统的评估机制,该机制使用 3 分钟的评估间隔和 5 分钟的回溯窗口。 回溯时间窗口用于确保在判断命名空间状态为正常之前至少 5 分钟没有错误。 在上面的示例中,命名空间在一两分钟后变得健康,但下一次评估发生在命名空间变得健康后的至少 5 分钟(回溯窗口)之后。
连接问题
连接到服务时超时
根据主机环境和网络情况,连接问题在应用程序中可能表现为 TimeoutException、OperationCanceledException,或者带有 ServiceBusException 的 ReasonServiceTimeout;这种情况通常发生在客户端找不到通往该服务的网络路径时。
若要进行故障排除:
- 验证创建客户端时指定的连接字符串或完全限定的域名是否正确。 有关如何获取连接字符串的信息,请参阅获取服务总线连接字符串。
- 检查托管环境中的防火墙和端口权限。 检查高级消息队列协议 (AMQP) 端口 5671 和 5672 是否已开放,以及是否允许通过防火墙访问终结点。
- 请尝试使用 Web 套接字传输选项,该选项使用端口 443 进行连接。 有关详细信息,请参阅配置传输。
- 查看网络是否阻止了特定 IP 地址。 有关详细信息,请参阅需要允许哪些 IP 地址?
- 如果适用,请验证代理配置。 有关详细信息,请参阅:配置传输
- 有关排查网络连接问题的详细信息,请参阅:连接性、证书或超时问题。
安全套接字层 (SSL) 握手失败
使用拦截代理时,可能会出现此错误。 若要验证,建议在禁用代理的主机环境中测试应用程序。
套接字资源耗尽错误
应用程序应优先将 Microsoft Azure 服务总线类型视为单一实例,并在应用程序的生存期内创建和使用单个实例。 每创建一个新的 ServiceBusClient,都会产生一个新的 AMQP 连接,而该连接会使用一个套接字。 ServiceBusClient 类型管理从该实例创建的所有类型的连接。 每个 ServiceBusReceiver、ServiceBusSessionReceiver、ServiceBusSender 以及 ServiceBusProcessor 为相关联的 Microsoft Azure 服务总线实体管理其自己的 AMQP 链接。 使用 ServiceBusSessionProcessor 时,会根据并发处理的会话数建立多个 AMQP 链接。
客户端在空闲时可以安全地缓存;它们将确保有效管理网络、CPU 和内存使用,最大限度地减少它们在不活动期间的影响。 此外,当不再需要客户端时,必须调用 CloseAsync 或 DisposeAsync,以确保正确清理网络资源。
将组件添加到连接字符串不起作用
当前一代的服务总线客户端库仅支持 Azure 门户发布的格式的连接字符串。 连接字符串仅用于提供基本位置和共享密钥信息。 客户端的行为可通过其选项进行配置。
以前几代的 Microsoft Azure 服务总线客户端允许通过将键/值组件添加到连接字符串来配置某些行为。 这些组件不再被识别,对客户端行为没有影响。
“TransportType=AmqpWebSockets”替代项
若要将 Web 套接字配置为传输类型,请参阅配置传输。
“Authentication=Managed Identity”替代方案
若要使用托管标识进行身份验证,请参阅:标识和共享访问凭据。 有关 Azure.Identity 库的详细信息,请参阅身份验证和 Azure SDK。
日志记录和诊断
服务总线 客户端库已完备支持日志记录,可使用 .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。 消息的跟踪方式是通过库在发送和计划操作期间设置到 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。
Note
有关详细信息,请参阅通过 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 分钟空闲超时而断开。 链接会在任何需要该链接的操作过程中自动重新建立,也就是说,在结算或接收消息时会自动重连。 在这种情况下,即使锁定到期时间尚未过去,你也会收到 ServiceBusException 为 Reason 或 MessageLockLost 的 SessionLockLost。
如何浏览计划消息或延迟消息
预览消息时,也会包括计划消息和延迟消息。 它们由 ServiceBusReceivedMessage.State 属性标识。 获取延迟消息的 SequenceNumber 后,可以通过 ReceiveDeferredMessagesAsync 方法以锁定方式接收该消息。
在处理主题时,无法速览订阅上的计划消息,因为这些消息一直保留在主题中,直到计划的排队时间。 作为一种变通方法,你可以构造一个 ServiceBusReceiver,并传入主题名称,以便查看此类消息。 使用主题名称时,对接收器执行的其他操作均无法使用。
如何浏览所有会话中的会话消息
可以使用常规 ServiceBusReceiver 速览所有会话。 若要查看特定会话,可以使用 ServiceBusSessionReceiver,但需要获取会话锁定。
访问消息正文时抛出 NotSupportedException
当收到从使用不同 AMQP 消息正文格式的不同库发送的消息时,通常会在互操作方案中出现此问题。 如果要与这些类型的消息交互,请参阅 AMQP 消息正文示例以了解如何访问消息正文。
同时打开多个接收器时出现“服务器繁忙”错误
如果在同一队列、主题或订阅上打开大量接收器,并同时保持它们处于活动状态,则可能会看到一个ServiceBusException,其Reason为ServiceBusy。 服务总线 在单个实体上最多允许有 5,000 个并发接收请求;对于主题,此限制按其所有订阅合并计算。 每个已打开的接收器都会发放信用并持续轮询消息——即使该实体为空也是如此——因此,大量空闲接收器可能会使合并后的接收请求总数超过此限制,额外的请求将被拒绝。
服务总线 SDK 会使用指数退避自动重试服务器繁忙响应,因此无需你手动处理这类暂时性情况。 为了避免达到限制,请将单个实体上的并发接收器数保持在 5,000 以下,关闭接收器不再需要,而不是将其保持空闲状态,如果需要大量使用者,请跨多个实体横向扩展。 有关详细信息,请参阅对Azure 服务总线的限制操作。
解决处理器问题
自动锁续订无法正常工作
自动锁定续订依赖于系统时间来确定何时续订消息或会话的锁定。 如果系统时间不准确,例如系统时钟走慢了,那么在锁丢失之前,可能无法完成锁续订。 如果自动锁定续订不起作用,请确保系统时间准确。
高并发时,处理器似乎会挂起或出现延迟问题
线程饥饿通常会导致此行为,尤其是在使用会话处理器和使用相对于机器上的核心数量非常高的 MaxConcurrentSessions 值时。 首先检查的是确保未在任何事件处理程序中执行异步中同步。 异步中同步是导致死锁和线程饥饿的一种简单方法。 即使未执行异步中同步,处理程序中的任何纯同步代码都可能导致线程饥饿。 例如,如果您确定这不是问题,例如因为您使用的是纯异步代码,则可以尝试增加TryTimeout。 它会通过减少在使用会话处理器时发生的上下文切换数量和超时来减轻线程池的压力。
TryTimeout 的默认值为 60 秒,但最多可设置为 1 小时。 我们建议以 TryTimeout 设置为 5 分钟作为测试起点,并从那里开始迭代。 如果上述任何建议都不起作用,则只需横向扩展到多个主机,减少应用程序中的并发性,但在多个主机上运行应用程序以实现所需的整体并发。
延伸阅读:
会话处理器切换会话的时间过长
可以使用 SessionIdleTimeout 配置此设置,该设置告知处理器在放弃并移动到另一个会话之前等待接收会话消息的时间。 如果你有很多消息较少的会话,并且每个会话都只有少量消息,这就很有用。 如果您预计每个会话中都会有大量消息陆续到达,那么将其设得过低可能会适得其反,因为这会导致会话被不必要地关闭。
处理器立即停止
对于演示或测试方案,通常会观察到此行为。
StartProcessingAsync 处理器启动后立即返回。 调用此方法不会阻止应用程序并在处理器运行时保持活动状态,因此需要其他一些机制来执行此作。 对于演示或测试,只需在启动处理器后添加 Console.ReadKey() 调用就足够了。 对于生产方案,你可能希望使用某种框架集成(如 BackgroundService )来提供方便的应用程序生命周期挂钩,可用于启动和释放处理器。
排查事务问题
有关 Microsoft Azure 服务总线中的事务的一般信息,请参阅服务总线事务处理概述。
支持的操作
使用事务时,并非所有操作都受支持。 若要查看支持的事务列表,请参阅事务范围内的操作。
Timeout
事务在经过一段时间后会超时,因此,在事务范围内执行的处理必须遵守这一超时时间限制。
事务中的操作不会被重试
此行为是设计造成的。 请考虑以下场景——你试图在事务中完成一条消息的处理,但此时发生了某种暂时性错误,例如,带有 ServiceBusExceptionReason 的 ServiceCommunicationProblem。 假设该请求确实到达了服务端。 如果客户端重试,该服务将看到两次完成请求。 在提交事务之前,不会最终确定第一次完成。 第二次 complete 操作甚至在第一次 complete 操作完成之前都无法被评估。 客户端上的事务正在等待 complete 操作完成。 它会导致一个死锁,其中服务等待客户端完成事务,而客户端则等待服务确认第二个完整操作的完成。 该事务最终会在 2 分钟后超时,但这是一种糟糕的用户体验。 因此,我们不会在事务中重试操作。
跨实体的事务不起作用
若要执行涉及多个实体的事务,需要将 ServiceBusClientOptions.EnableCrossEntityTransactions 属性设置为 true。 有关详细信息,请参阅跨实体的事务示例。
Quotas
可在此处找到有关 Microsoft Azure 服务总线配额的信息。
连接、证书或超时问题
以下步骤可帮助排查 *.servicebus.chinacloudapi.cn 下所有服务的连接性/证书/超时问题。
浏览到该地址或使用 wget
https://<yournamespace>.servicebus.chinacloudapi.cn/。 这可帮助检查是否存在 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 端口的示例命令。
tnc <yournamespacename>.servicebus.chinacloudapi.cn -port 5671在 Linux 上:
telnet <yournamespacename>.servicebus.chinacloudapi.cn 5671出现间歇性连接问题时,请运行以下命令,检查是否存在任何丢弃的数据包。 此命令尝试每 1 秒与服务建立 25 个不同的 TCP 连接。 然后,可以检查其中有多少成功/失败,还可以查看 TCP 连接延迟。 您可以从
psping下载工具。.\psping.exe -n 25 -i 1 -q <yournamespace>.servicebus.chinacloudapi.cn:5671 -nobanner如果使用的是其他工具(如
tnc、ping等),则可以使用等效的命令。如果上述步骤没有帮助,请获取网络跟踪,并使用 Wireshark 之类的工具对其进行分析。 如果需要,请联系 Azure 支持部门。
若要查找要添加到连接允许列表的正确 IP 地址,请参阅我需要添加到允许列表的 IP 地址。
Note
2026 年 9 月 30 日,我们将不再支持 Azure 服务总线的 SBMP 协议,因此在 2026 年 9 月 30 日之后,你将无法再使用此协议。 请在该日期之前迁移到最新的使用 AMQP 协议的 Azure 服务总线 SDK 库,新库提供了关键安全更新和改进功能。
有关详细信息,请参阅支持停用公告。
服务升级/重启时可能出现的问题
Symptoms
- 请求可能会暂时受到限制。
- 传入的消息/请求可能会减少。
- 日志文件可能包含错误消息。
- 应用程序可能会与服务断开连接几秒钟。
Cause
后端服务升级和重启可能会在应用程序中导致这些问题。
Resolution
如果应用程序代码使用 SDK,则重试策略已内置且处于活动状态。 应用程序会重新连接,此操作不会对应用程序/工作流产生重大影响。
未授权访问:需要发送声明
Symptoms
在本地计算机上的 Visual Studio 中,尝试使用具有发送权限的用户分配托管标识访问 服务总线 主题时,可能会看到此错误。
Service Bus Error: Unauthorized access. 'Send' claim\(s\) are required to perform this operation.
Cause
该标识没有访问服务总线主题的权限。
Resolution
要解决此错误,请安装 Microsoft.Azure.Services.AppAuthentication 库。 有关详细信息,请参阅本地开发身份验证。
要了解如何将权限分配给角色,请参阅使用 Microsoft Entra ID 对托管标识进行身份验证,以便访问 Azure 服务总线资源。
服务总线异常:put-token 失败
Symptoms
看到以下错误消息:
Microsoft.Azure.ServiceBus.ServiceBusException: Put token failed. status-code: 403, status-description: The maximum number of '1000' tokens per connection has been reached.
Note
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 的官方支持和更新。 有关详细信息,请参阅支持停用公告。
Cause
单个连接到服务总线命名空间的并发链接的身份验证令牌数超过了限制:1000。
Resolution
执行以下步骤中的一个:
- 减少单个连接中的并发链接数或使用新连接
- 将 SDK 用于 Azure 服务总线,这可确保不会遇到这种情况(推荐)
使用数据平面 SDK 时,资源锁不起作用
Symptoms
在服务总线命名空间上配置了删除锁,但可以使用服务总线资源管理器删除命名空间(队列、主题等)中的资源。
Cause
资源锁保留在 Azure 资源管理器(控制平面)中,它不会阻止数据平面 SDK 调用直接从命名空间中删除资源。 独立版 服务总线 Explorer 使用数据平面 SDK,因此删除操作可以成功执行。
Resolution
建议通过 Azure 门户、PowerShell、CLI 或 资源管理器模板使用基于 Azure 资源管理器的 API 来删除实体,以便资源锁可防止意外删除资源。
实体不再可用
Symptoms
你看到一条错误消息,提示该实体不再可用。
Cause
资源可能已被删除。 请按照以下步骤确定实体被删除的原因。
- 检查活动日志以查看是否存在 Azure 资源管理器删除请求。
- 检查操作日志以查看是否有用于删除的直接 API 调用。 若要了解如何收集运行日志,请参阅监视 Azure 服务总线。 有关操作日志的架构和示例,请参阅操作日志
- 检查操作日志以查看是否存在
autodeleteonidle相关删除。
实体名称显示波形符(~)而不是正斜杠(/)
Symptoms
Azure门户、CLI 或 ARM API 响应中的实体名称显示 ~ 字符,例如 orders~cn~east2 而不是 orders/cn/east2。
Cause
服务总线支持将 / 作为路径分隔符的分层实体名称,但Azure 资源管理器不允许资源名称中的 /。 服务总线将 ~ 转换为 ARM 边界处的 /。
Resolution
这是预期的行为。 基础实体名称使用 /。 仅 ~ 显示在基于 ARM 的工具(门户、CLI、PowerShell、ARM 模板)中。 服务总线 SDK 和 AMQP 客户端会看到实际的 / 名称。 有关详情,请参阅带正斜杠的实体名称。
后续步骤
请参阅以下文章:
- Azure 资源管理器异常。 这篇文章列出了使用 Azure 资源管理器(通过模板或直接调用)与 Azure 服务总线进行交互时生成的异常。
- 消息传送异常。 这篇文章列出了 Azure 服务总线的 .NET Framework 生成的异常。