排查Azure 服务总线问题

本文介绍故障调查技术、并发性、Azure 服务总线 Java 客户端库中凭据类型的常见错误,以及解决这些错误的缓解步骤。

启用和配置日志记录

Azure SDK for Java 提供了一致的日志记录故事,可帮助排查应用程序错误并帮助加快解决速度。 生成的日志会在到达终端状态之前捕获应用程序的流,以帮助查找根本问题。 有关日志记录的指导,请参阅 Azure SDK for Java 中的日志记录和 故障排除概述

除了启用日志记录之外,还可以将日志级别设置为 VERBOSEDEBUG 提供有关库状态的见解。 以下部分演示了示例 log4j2 和 logback 配置,以便在启用详细日志记录时减少过多的消息。

配置 Log4J 2

使用以下步骤配置 Log4J 2:

  1. 在“Log4j2 所需的依赖项”部分中,使用日志记录示例pom.xml中的依赖项添加到pom.xml
  2. 将log4j2.xml添加到 src/main/resources 文件夹。

配置 logback

使用以下步骤配置 logback:

  1. 在“logback 所需的依赖项”部分中,使用日志记录示例pom.xml中的依赖项添加到pom.xml
  2. 将logback.xml添加到 src/main/resources 文件夹。

启用 AMQP 传输日志记录

如果启用客户端日志记录不足以诊断问题,则可以启用对基础 AMQP 库 Qpid Proton-J 中的文件进行日志记录。 Qpid Proton-J 使用 java.util.logging。 可以通过创建包含下一部分所示内容的配置文件来启用日志记录。 或者,为实现设置 proton.trace.level=ALL 和所需的 java.util.logging.Handler 配置选项。 有关实现类及其选项,请参阅 Java 8 SDK 文档中的 Package java.util.logging

若要跟踪 AMQP 传输帧,请设置 PN_TRACE_FRM=1 环境变量。

示例 logging.properties 文件

以下配置文件将 Proton-J 的 TRACE 级别输出记录到文件 proton-trace.log

handlers=java.util.logging.FileHandler
.level=OFF
proton.trace.level=ALL
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=proton-trace.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tr] %3$s %4$s: %5$s %n

减少日志记录

减少日志记录的一种方法是更改详细程度。 另一种方法是添加从记录器名称包中排除日志的筛选器,例如 com.azure.messaging.servicebuscom.azure.core.amqp。 有关示例,请参阅“配置 Log4J 2”和“配置 logback”部分中的 XML 文件。

提交 bug 时,以下包中类的日志消息很有趣:

  • com.azure.core.amqp.implementation
  • com.azure.core.amqp.implementation.handler
    • 例外情况是可以忽略onDelivery消息。ReceiveLinkHandler
  • com.azure.messaging.servicebus.implementation

ProcessorClient 中的并发

ProcessorClient 使应用程序能够配置对消息处理程序的调用应同时发生的次数。 此配置使可以并行处理多个消息。 ProcessorClient对于来自非会话实体的消耗消息,应用程序可以使用 API 配置所需的并发。maxConcurrentCalls 对于启用会话的实体,所需的并发是 maxConcurrentSessions 时间 maxConcurrentCalls

如果应用程序观察到对消息处理程序的并发调用数少于配置的并发性,则可能是因为线程池的大小不正确。

ProcessorClient 使用 Reactor 全局 boundedElastic 线程池中的守护程序线程调用消息处理程序。 此池中的最大并发线程数受上限限制。 默认情况下,此上限是可用 CPU 内核数的十倍。 ProcessorClient为了有效地支持应用程序的所需并发(maxConcurrentCallsmaxConcurrentSessions时间maxConcurrentCalls),必须具有boundedElastic高于所需并发的池上限值。 可以通过设置系统属性 reactor.schedulers.defaultBoundedElasticSize来替代默认上限。

应逐个情况优化线程池和 CPU 分配。 但是,当重写池上限(作为起点)时,将并发线程限制为每个 CPU 核心大约 20-30 个。 建议将每个 ProcessorClient 实例的所需并发限制为大约 20-30。 分析并衡量特定用例,并相应地优化并发方面。 对于高负载方案,请考虑运行多个 ProcessorClient 实例,其中每个实例都是从新 ServiceBusClientBuilder 实例生成的。 此外,请考虑在专用主机(例如容器或 VM)中运行每个 ProcessorClient 主机,以便一个主机中的停机时间不会影响整个消息处理。

请记住,在具有少量 CPU 核心的主机上为池上限设置高值将产生负面影响。 CPU 资源不足或 CPU 使用率过多的池的一些迹象是:频繁超时、锁丢失、死锁或吞吐量较低。 如果要在容器上运行 Java 应用程序,建议使用两个或多个 vCPU 核心。 在容器化环境中运行 Java 应用程序时,不建议选择小于 1 个 vCPU 核心的内容。 有关资源准备的深入建议,请参阅 容器化 Java 应用程序

升级到 7.15.x 或最新版

如果遇到任何问题,应首先尝试通过升级到最新版本的 服务总线 SDK 来解决这些问题。 版本 7.15.x 是一项重大重新设计,解决了长期的性能和可靠性问题。

版本 7.15.x 及更高版本可减少线程跳跃、删除锁、优化热路径中的代码,并减少内存分配。 这些更改会导致客户端的 ServiceBusProcessor 吞吐量增加 45-50 倍。

版本 7.15.x 及更高版本还附带了各种可靠性改进。 它解决了多种争用情况(如预提取和信用计算),并改进了错误处理。 这些更改会导致在各种客户端类型中出现暂时性问题时获得更好的可靠性。

使用最新的客户端

这些改进的新基础框架(在版本 7.15.x 及更高版本中)称为 V2-Stack。 此发布行包括上一代的基础堆栈(版本 7.14.x 使用的堆栈)和新版 V2-Stack。

默认情况下,某些客户端类型使用 V2-Stack,而其他客户端类型则要求使用 V2-Stack 选择加入。 可以通过在生成客户端时提供 com.azure.core.util.Configuration 值来实现对客户端类型的特定堆栈(V2 或上一代)的选择加入或退出。

例如,基于 V2 Stack 的会话接收 ServiceBusSessionReceiverClient 需要选择加入,如以下示例所示:

ServiceBusSessionReceiverClient sessionReceiver = new ServiceBusClientBuilder()
    .connectionString(Config.CONNECTION_STRING)
    .configuration(new com.azure.core.util.ConfigurationBuilder()
        .putProperty("com.azure.messaging.servicebus.session.syncReceive.v2", "true") // 'false' by default, opt-in for V2-Stack.
        .build())
    .sessionReceiver()
    .queueName(Config.QUEUE_NAME)
    .buildClient();

下表列出了客户端类型和相应的配置名称,并指示客户端当前是否在最新版本 7.16.0 中使用 V2-Stack。 对于默认不在 V2-Stack 上的客户端,可以使用刚刚显示的示例来选择加入。

客户端类型 配置名称 V2 堆栈默认是否在?
发送方和管理客户端 com.azure.messaging.servicebus.sendAndManageRules.v2
非会话处理器和反应器接收器客户端 com.azure.messaging.servicebus.nonSession.asyncReceive.v2
会话处理器接收器客户端 com.azure.messaging.servicebus.session.processor.asyncReceive.v2
会话反应器接收器客户端 com.azure.messaging.servicebus.session.reactor.asyncReceive.v2
非会话同步接收器客户端 com.azure.messaging.servicebus.nonSession.syncReceive.v2
会话同步接收器客户端 com.azure.messaging.servicebus.session.syncReceive.v2

作为使用替代方法 com.azure.core.util.Configuration,可以使用环境变量或系统属性设置相同的配置名称来选择加入或选择退出。

后续步骤

如果本文中的故障排除指南在使用 Azure SDK for Java 客户端库时无法解决问题,建议在 Azure SDK for Java GitHub 存储库提出问题。