Azure 服务总线故障排除指南

本文提供的故障排除技巧和建议适用于你在使用 Azure 服务总线时看到的一些问题。

在排查客户故障前,先检查服务健康状况

首先确认Azure 服务总线在您所在地区的使用状况是否良好。 这个快速检查告诉你应该重点排查哪里。 先从这两个检查开始:

  1. 查看 Azure 服务运行状况。 在Azure门户中,打开Azure 服务运行状况或进入Azure状态页面,查看您所在地区服务总线是否有活跃的健康事件或公告。 服务健康报告会报告影响特定目标客户群的服务端事件,例如某个地区的部分客户。
  2. 检查你的命名空间的资源运行状况。 在 Azure 门户中,打开你的 服务总线 命名空间,选择资源健康。 资源运行状况 显示你特定命名空间当前和近期的健康状况。 有关详细信息,请参阅 Azure 资源运行状况概述

如果任一检查显示服务端事件活跃,则该服务很可能是该服务的来源。 服务总线 SDK 内置的重试策略会自动重试暂时故障并在短暂中断后重新连接。 长时间的中断可能超过内置重试限制,因此请确保你的应用在服务恢复后也重试或恢复处理。 如果两次检查都显示服务正常,请继续进行本文后续的客户端故障排除。

资源健康状况

在 Azure 门户中服务总线命名空间的资源 运行状况 页上标记的不正常时间段可能比实际时间段长几分钟。 例如,页面可能指示命名空间在 5-6 分钟内运行不正常,而实际运行不正常的时间段仅为 1-2 分钟。

此行为是由于警报系统的评估机制,该机制使用 3 分钟的评估间隔和 5 分钟的回溯窗口。 回溯时间窗口用于确保在判断命名空间状态为正常之前至少 5 分钟没有错误。 在上面的示例中,命名空间在一两分钟后变得健康,但下一次评估发生在命名空间变得健康后的至少 5 分钟(回溯窗口)之后。

连接问题

连接到服务时超时

根据主机环境和网络情况,连接问题在应用程序中可能表现为 TimeoutExceptionOperationCanceledException,或者带有 ServiceBusExceptionReasonServiceTimeout;这种情况通常发生在客户端找不到通往该服务的网络路径时。

若要进行故障排除:

  • 验证创建客户端时指定的连接字符串或完全限定的域名是否正确。 有关如何获取连接字符串的信息,请参阅获取服务总线连接字符串
  • 检查托管环境中的防火墙和端口权限。 检查高级消息队列协议 (AMQP) 端口 5671 和 5672 是否已开放,以及是否允许通过防火墙访问终结点。
  • 请尝试使用 Web 套接字传输选项,该选项使用端口 443 进行连接。 有关详细信息,请参阅配置传输
  • 查看网络是否阻止了特定 IP 地址。 有关详细信息,请参阅需要允许哪些 IP 地址?
  • 如果适用,请验证代理配置。 有关详细信息,请参阅:配置传输
  • 有关排查网络连接问题的详细信息,请参阅:连接性、证书或超时问题

发送或接收操作超时

大多数发送和接收超时通常只是暂时的,并且会自行恢复。 某些超时情况表明服务端存在需要你检查的问题。 本节帮助你区分这两种类型的超时,并选择合适的应对方式。

临时性超时会自行恢复

瞬时超时是指短暂中断,例如瞬时网络抖动、正在重新建立的连接,或负载短时激增。 客户端库会使用内置的重试策略自动重试暂时性故障,包括超时错误。 默认策略最多重试三次,采用指数退避,并将每次尝试的超时时间设为 60 秒(TryTimeout),因此大多数暂时性超时都会自行恢复,无需你采取任何操作。

为了让SDK来处理这项工作:

  • 保留默认的重试策略。 这会为 SDK 留出从瞬时性故障中恢复的余地。 降低最大重试次数或 TryTimeout 会减少这种余地,因此,除非你有充分的理由更改它们,否则请保持默认设置。
  • 具有 ServiceBusException(值为 Reason)的 ServiceTimeout(或 SDK 中等效的瞬态错误)可以安全地重试,因此可以让 SDK 自动重试,或者自行重试该操作。
  • 下一次呼叫成功且单次超时是可以预期的,无需操作。

何时检查服务端

如果超时在多次重试和重启客户端后仍然持续出现,而不是自行恢复,请检查服务的健康状况。 寻找两种图案:

  • 一个无反应的实体。 单个队列、主题或订阅停止响应,而命名空间的其他部分继续工作。 即使与命名空间的连接正常,针对该实体的发送和接收操作仍会超时。
  • 内部服务器错误的增加。 整个命名空间中的请求开始返回内部服务器错误,例如,ServiceBusExceptionReasonServiceCommunicationProblem,或者 AMQP amqp:internal-error。 持续上升,而不是偶尔出现的可重试错误,表明这是服务端异常所致。

为了确认并寻求帮助:

  • 在 Azure 门户中打开你命名空间的资源健康页面,查看服务报告的健康状况。 有关详细信息,请参阅资源运行状况
  • 在 Azure 门户中,关注服务器错误指标。 服务器错误持续上升,指向服务端而非客户端。 有关度量定义,请参见 Monitoring Azure 服务总线 data reference
  • 如果你也看到“ 限速请求 ”指标上升,说明命名空间已达到吞吐量或资源极限。 这是容量问题,而非服务故障,因此应通过降低负载或扩展,比如在高级套餐中添加消息单元来解决。 欲了解更多信息,请参见 Azure 服务总线 中的 Throttling
  • 通过解决 连接性、证书或超时问题,确认不是客户端造成的。
  • 如果资源健康报告问题,平台会检测并努力缓解。 SDK 会自动通过短暂中断重新连接,但服务端事件时间更长可能会超过重试限制,因此服务恢复后请让应用重试或恢复处理。 持续监控资源健康状态,直到其恢复正常。
  • 如果资源健康显示命名空间正常,但仍然出现单个无响应实体或服务器错误持续上升,请发起支持请求,让团队调查服务端。

设置接收等待的时间

接收呼叫等待消息多久才返回取决于SDK本身。 如果接收器等待时间比预期更长,通常是因为没有设置等待限制,而不是服务本身的问题。

  • 在 .NET、Java 和 JavaScript 库中,接收操作默认情况下是有界的。 最大等待时间默认为60秒,之后如果没有消息到达,呼叫返回空结果。

  • 在 Python 库中,max_wait_time默认为 None,因此调用等待消息到达或连接关闭。 设置一个 max_wait_time 值来限定其范围。

  • 在 Go 库中,ReceiveMessages 的超时时间取自你传入的 context.Context,并且它会一直等待,直到至少有一条消息到达或该上下文被取消。 传递一个带有截止日期的上下文,以设置接收等待的时间:

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    messages, err := receiver.ReceiveMessages(ctx, 10, nil)
    

在 Go 和 Python 中,设置上下文截止时间(Go)或max_wait_time值(Python)会给你可预测的接收行为。

安全套接字层 (SSL) 握手失败

使用拦截代理时,可能会出现此错误。 若要验证,建议在禁用代理的主机环境中测试应用程序。

套接字资源耗尽错误

应用程序应优先将 Microsoft Azure 服务总线类型视为单一实例,并在应用程序的生存期内创建和使用单个实例。 每创建一个新的 ServiceBusClient,都会产生一个新的 AMQP 连接,而该连接会使用一个套接字。 ServiceBusClient 类型管理从该实例创建的所有类型的连接。 每个 ServiceBusReceiverServiceBusSessionReceiverServiceBusSender 以及 ServiceBusProcessor 为相关联的 Microsoft Azure 服务总线实体管理其自己的 AMQP 链接。 使用 ServiceBusSessionProcessor 时,会根据并发处理的会话数建立多个 AMQP 链接。

客户端在空闲时可以安全地缓存;它们将确保有效管理网络、CPU 和内存使用,最大限度地减少它们在不活动期间的影响。 此外,当不再需要客户端时,必须调用 CloseAsyncDisposeAsync,以确保正确清理网络资源。

将组件添加到连接字符串不起作用

当前一代的服务总线客户端库仅支持 Azure 门户发布的格式的连接字符串。 连接字符串仅用于提供基本位置和共享密钥信息。 客户端的行为可通过其选项进行配置。

以前几代的 Microsoft Azure 服务总线客户端允许通过将键/值组件添加到连接字符串来配置某些行为。 这些组件不再被识别,对客户端行为没有影响。

“TransportType=AmqpWebSockets”替代项

若要将 Web 套接字配置为传输类型,请参阅配置传输

“Authentication=Managed Identity”替代方案

若要使用托管标识进行身份验证,请参阅:标识和共享访问凭据。 有关 Azure.Identity 库的详细信息,请参阅身份验证和 Azure SDK

托管标识身份验证失败

当你的应用程序用托管身份而非连接字符串进行认证时,即使服务的网络路径是健康的,连接尝试也可能因授权错误而失败。 根据 SDK 的不同,失败可能表现为 Unauthorized 错误、带有与授权相关原因的 ServiceBusException,或者“Put token failed”错误。

这些失败来自宿主环境中的令牌获取或角色分配,而非 服务总线 客户端。 每个 服务总线 SDK(.NET、Java、JavaScript、Python 和 Go)都有同样的原因,因为每个 SDK 都通过 Azure Identity 库获取 Microsoft Entra 令牌。

若要解决此问题,请执行以下操作:

  • 确认该身份在命名空间、队列或主题上有 Azure 角色分配。 发送需要使用 Azure 服务总线 数据发送者角色,接收则需要使用 Azure 服务总线 Data Receiver 角色。 步骤请参见“用 Microsoft Entra ID 认证管理身份以访问 Azure 服务总线 资源
  • 确认客户端请求令牌作用域 https://servicebus.azure.net/.default。 发行代币 aud (受众)的权利要求为 https://servicebus.azure.net。 角色分配是与范围不同的要求,所以也要核实。
  • 请确认 DefaultAzureCredential 选择的是预期的凭据。 当主机中有多个凭据可用时,DefaultAzureCredential 会使用其解析顺序中的第一个凭据。 启用 Azure 身份日志,或明确指定凭证以确认使用的身份。 关于 .NET 凭证解析顺序及更多故障排除步骤,请参见 DefaultAzureCredentialTroubleshoot Azure Identity 认证问题。 每种语言的 Azure 身份库都遵循相同的凭证链。
  • 请等待新的角色分配生效,这可能需要几分钟时间。
  • 检查主机时钟是否准确且同步。 Microsoft Entra ID 验证令牌是否符合其发行时间和到期时间。

Note

Azure 服务总线 数据角色(Azure 服务总线 数据发送者Azure 服务总线 数据接收者Azure 服务总线 数据所有者)控制数据平面访问权限。 它们与管理层角色(如 所有者贡献者)是分开的,后者管理的是资源而非数据。

Azure Kubernetes 服务 (AKS) 工作负载标识

当你在启用工作负载标识的 AKS 上运行时,前面的检查仍然适用。 还要验证工作负载身份配置:

  • Kubernetes 服务账户会标注身份的客户端 ID。
  • 舱体上有 azure.workload.identity/use 标签。
  • 联邦身份凭据将管理身份或 Microsoft Entra 应用与集群的 OpenID Connect(OIDC)发行机构连接起来。

要为 AKS 集群分配托管身份,请参见“迁移应用使用无密码连接”中的 Azure Kubernetes 服务 标签页。

日志记录和诊断

服务总线 客户端库已完备支持日志记录,可使用 .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.SendServiceBusReceiver.ReceiveServiceBusSessionProcessor.ProcessSessionMessageServiceBusReceiver.Complete

排查发送方问题

无法发送具有多个分区键的批次

当应用将一个批次发送到启用了分区的实体时,单个发送操作中包含的所有消息必须具有相同的 PartitionKey。 如果实体已启用会话,则对 SessionId 属性也有相同的要求。 若要发送具有不同 PartitionKeySessionId 值的消息,请将消息分组在单独的 ServiceBusMessageBatch 实例中,或将它们包含在对 SendMessagesAsync 重载(采用一组 ServiceBusMessage 实例)的单独调用中。

批次无法发送

一个消息批次是包含两条或多条消息的 ServiceBusMessageBatch,或者是对 SendMessagesAsync 的调用(其中传入两条或更多消息)。 该服务不允许一个消息批次超过 1 MB。 无论是否启用“高级大型消息支持”功能,此行为都是如此。 如果想要发送大于 1 MB 的消息,则必须单独发送它,而不是与其他消息分组发送。 遗憾的是,ServiceBusMessageBatch 类型目前不支持验证某个批次是否包含任何大于 1MB 的消息,因为大小受服务限制,这可能会更改。 因此,如果打算使用高级大型消息支持功能,请确保单独发送超过 1 MB 的消息。

排查接收器问题

返回的消息数与批量接收中请求的数量不匹配

当尝试执行批量接收操作时,也就是说,将 maxMessages 值 2 或更大值传递给 ReceiveMessagesAsync 方法时,即使队列或订阅当时有许多可用消息,并且即使整个配置的 maxWaitTime 尚未过期,也不能保证接收到请求的消息数。 为了最大程度地提高吞吐量并避免锁定过期,一旦第一条消息通过网络,接收方会等待额外的 20 毫秒等待任何额外的消息,然后调度消息进行处理。 maxWaitTime 控制接收方等待接收第一条消息的时长 - 随后的消息会等待 20 毫秒。 因此,应用程序不应假定所有可用的消息都会在一次调用中接收。

消息或会话锁在过期前丢失

服务总线服务使用 AMQP 协议,该协议是有状态的。 由于协议的性质,如果连接客户端和服务的链路在接收消息后但在消息解决之前拆离,则无法在重新连接链路时解决该消息。 连接可能会因短暂的瞬时网络故障、网络中断或服务强制执行的 10 分钟空闲超时而断开。 链接会在任何需要该链接的操作过程中自动重新建立,也就是说,在结算或接收消息时会自动重连。 在这种情况下,即使锁定到期时间尚未过去,你也会收到 ServiceBusExceptionReasonMessageLockLostSessionLockLost。 如果一条消息被重复接收,但由于锁已丢失而始终未被确认处理,则其投递计数会不断增加,直到该消息被移到死信队列中。 更多信息请参见《 为什么我的消息进入了死信队列?》

如何浏览计划消息或延迟消息

预览消息时,也会包括计划消息和延迟消息。 它们由 ServiceBusReceivedMessage.State 属性标识。 获取延迟消息的 SequenceNumber 后,可以通过 ReceiveDeferredMessagesAsync 方法以锁定方式接收该消息。

在处理主题时,无法速览订阅上的计划消息,因为这些消息一直保留在主题中,直到计划的排队时间。 作为一种变通方法,你可以构造一个 ServiceBusReceiver,并传入主题名称,以便查看此类消息。 使用主题名称时,对接收器执行的其他操作均无法使用。

如何浏览所有会话中的会话消息

可以使用常规 ServiceBusReceiver 速览所有会话。 若要查看特定会话,可以使用 ServiceBusSessionReceiver,但需要获取会话锁定。

访问消息正文时抛出 NotSupportedException

当收到从使用不同 AMQP 消息正文格式的不同库发送的消息时,通常会在互操作方案中出现此问题。 如果要与这些类型的消息交互,请参阅 AMQP 消息正文示例以了解如何访问消息正文。

同时打开多个接收器时出现“服务器繁忙”错误

如果在同一队列、主题或订阅上打开大量接收器,并同时保持它们处于活动状态,则可能会看到一个ServiceBusException,其ReasonServiceBusy。 服务总线 在单个实体上最多允许有 5,000 个并发接收请求;对于主题,此限制按其所有订阅合并计算。 每个已打开的接收器都会发放信用并持续轮询消息——即使该实体为空也是如此——因此,大量空闲接收器可能会使合并后的接收请求总数超过此限制,额外的请求将被拒绝。

服务总线 SDK 会使用指数退避自动重试服务器繁忙响应,因此无需你手动处理这类暂时性情况。 为了避免达到限制,请将单个实体上的并发接收器数保持在 5,000 以下,关闭接收器不再需要,而不是将其保持空闲状态,如果需要大量使用者,请跨多个实体横向扩展。 有关详细信息,请参阅对Azure 服务总线的限制操作

解决处理器问题

自动锁续订无法正常工作

自动锁定续订依赖于系统时间来确定何时续订消息或会话的锁定。 如果系统时间不准确,例如系统时钟走慢了,那么在锁丢失之前,可能无法完成锁续订。 如果自动锁定续订不起作用,请确保系统时间准确。

高并发时,处理器似乎会挂起或出现延迟问题

线程饥饿通常会导致此行为,尤其是在使用会话处理器和使用相对于机器上的核心数量非常高的 MaxConcurrentSessions 值时。 首先检查的是确保未在任何事件处理程序中执行异步中同步。 异步中同步是导致死锁和线程饥饿的一种简单方法。 即使未执行异步中同步,处理程序中的任何纯同步代码都可能导致线程饥饿。 例如,如果您确定这不是问题,例如因为您使用的是纯异步代码,则可以尝试增加TryTimeout。 它会通过减少在使用会话处理器时发生的上下文切换数量和超时来减轻线程池的压力。 TryTimeout 的默认值为 60 秒,但最多可设置为 1 小时。 我们建议以 TryTimeout 设置为 5 分钟作为测试起点,并从那里开始迭代。 如果上述任何建议都不起作用,则只需横向扩展到多个主机,减少应用程序中的并发性,但在多个主机上运行应用程序以实现所需的整体并发。

延伸阅读:

会话处理器切换会话的时间过长

可以使用 SessionIdleTimeout 配置此设置,该设置告知处理器在放弃并移动到另一个会话之前等待接收会话消息的时间。 如果你有很多消息较少的会话,并且每个会话都只有少量消息,这就很有用。 如果您预计每个会话中都会有大量消息陆续到达,那么将其设得过低可能会适得其反,因为这会导致会话被不必要地关闭。

处理器立即停止

对于演示或测试方案,通常会观察到此行为。 StartProcessingAsync 处理器启动后立即返回。 调用此方法不会阻止应用程序并在处理器运行时保持活动状态,因此需要其他一些机制来执行此作。 对于演示或测试,只需在启动处理器后添加 Console.ReadKey() 调用就足够了。 对于生产方案,你可能希望使用某种框架集成(如 BackgroundService )来提供方便的应用程序生命周期挂钩,可用于启动和释放处理器。

排查事务问题

有关 Microsoft Azure 服务总线中的事务的一般信息,请参阅服务总线事务处理概述

支持的操作

使用事务时,并非所有操作都受支持。 若要查看支持的事务列表,请参阅事务范围内的操作

Timeout

事务在经过一段时间后会超时,因此,在事务范围内执行的处理必须遵守这一超时时间限制。

事务中的操作不会被重试

此行为是设计造成的。 请考虑以下场景——你试图在事务中完成一条消息的处理,但此时发生了某种暂时性错误,例如,带有 ServiceBusExceptionReasonServiceCommunicationProblem。 假设该请求确实到达了服务端。 如果客户端重试,该服务将看到两次完成请求。 在提交事务之前,不会最终确定第一次完成。 第二次 complete 操作甚至在第一次 complete 操作完成之前都无法被评估。 客户端上的事务正在等待 complete 操作完成。 它会导致一个死锁,其中服务等待客户端完成事务,而客户端则等待服务确认第二个完整操作的完成。 该事务最终会在 2 分钟后超时,但这是一种糟糕的用户体验。 因此,我们不会在事务中重试操作。

跨实体的事务不起作用

若要执行涉及多个实体的事务,需要将 ServiceBusClientOptions.EnableCrossEntityTransactions 属性设置为 true。 有关详细信息,请参阅跨实体的事务示例。

Quotas

可在此处找到有关 Microsoft Azure 服务总线配额的信息。

连接、证书或超时问题

以下步骤可帮助排查 *.servicebus.chinacloudapi.cn 下所有服务的连接性/证书/超时问题。

  • 浏览到该地址或使用 wgethttps://<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     
    

    如果使用的是其他工具(如 tncping 等),则可以使用等效的命令。

  • 如果上述步骤没有帮助,请获取网络跟踪,并使用 Wireshark 之类的工具对其进行分析。 如果需要,请联系 Azure 支持部门

  • 若要查找要添加到连接允许列表的正确 IP 地址,请参阅我需要添加到允许列表的 IP 地址

TLS证书链及中间证书问题

服务总线端点(*.servicebus.chinacloudapi.cn)提供TLS证书,串联到公共根证书授权中心(CA)。 Azure定期轮换该链中的 TLS 证书和中间 CA。 如果您的客户端的受信任证书存储中缺少更新后的中间 CA 证书,或者您的客户端固定了特定的中间 CA 证书或叶子证书,那么即使您的应用程序没有任何变化,TLS 握手也会在轮换后失败。

症状包括TLS或SSL握手失败、证书链验证错误(如 unable to get local issuer certificate,或连接在证书轮换前正常,轮换后开始失效)。

若要解决此问题,请执行以下操作:

  • 应信任根 CA,而不是固定中间证书或叶子证书。 Azure轮换中间证书,因此信任根会使客户端跨轮换工作。 关于 Azure 服务当前使用的根和中间 CA,请参见 Azure 证书授权机构详情

  • 更新操作系统或运行时信任存储,以包含当前的CA证书。 在 Linux 上,更新 CA 证书包,例如 ca-certificates 软件包。 对于 Java,确保 JRE cacerts 的 truststore 是最新的,因为 Java 验证证书是基于自身的 truststore 而非操作系统的。

  • 如果你使用自定义或企业受信任证书存储,请将当前的 Azure 根 CA 和中间 CA 添加到其中。

  • 确认任何拦截代理或TLS检测设备是否显示客户信任的证书链。

Important

通过使用正确的 CA 证书更新信任存储,解决证书链验证失败问题。 保持TLS证书验证功能开启。 绕过验证会移除对中间人攻击的保护,例如通过设置 NODE_TLS_REJECT_UNAUTHORIZED=0 Node.js 或安装接受任何证书的证书验证回调。

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 生成的异常。