上一章 目录 索引 下一章 |
Sun Java System Message Queue 3.5 SP1 管理指南

> ## 第 9 章
> 分析和调整消息服务

> 本章包括大量有关如何分析和调整 Message Queue 服务以优化消息传送应用程序性能的主题。包括下列主题：

> - 关于性能
> - 影响性能的因素
> - 监视消息服务器
> - 性能问题疑难解答
> - 调整配置以提高性能

> ##

> 关于性能

> ### 性能调整过程

> 您的消息传送应用程序的性能取决于该应用程序与 Message Queue 服务之间的交互。因此，若要获得最佳性能，则需要应用程序开发者和管理员的共同努力。

> 优化性能的过程从应用程序设计开始，一直持续到部署应用程序之后对消息服务的调整阶段。性能调整过程包括下列阶段：

> - 定义应用程序的性能要求
> - 设计的应用程序要考虑到影响性能的因素（特别是可靠性和性能之间的折衷）
> - 建立性能衡量基线
> - 调整或重新配置消息服务以优化性能。

> 上述过程常常需要反复进行。在应用程序的部署过程中，Message Queue 管理员应该评估消息服务器是否适用于应用程序的总体性能要求。如果基准检验测试符合这些要求，管理员就可以按本章中所述调整系统。但是，如果基准检验测试不符合性能要求，则可能需要重新设计应用程序或者修改部署体系结构。

> ### 性能方面

> 通常，性能是对消息服务将消息从生成方传送到使用方时的速度和效率的一种衡量。但是，取决于您的需要，可能会有几个不同的性能方面对您特别重要。

> 连接负荷 系统所能支持的消息生成方、消息使用方或并行连接的数量。

> 消息吞吐量 每秒钟能通过消息传送系统抽取的消息数或消息字节数。

> 延迟 特定消息从消息生成方传送到消息使用方所需的时间。

> 稳定性 消息服务的总体可用性，或者当负荷较重或发生故障时性能的下降程度。

> 效率 消息的传送效率，这是一种与使用的计算资源相关的消息吞吐量的衡量。

> 这些不同的性能方面总而言之是相辅相成的。如果消息吞吐量很高，则意味着消息在消息服务器上作为待办事项累积的可能性就会变小，因此延迟时间也应该较低（单条消息可以很快地传送）。但是，延迟可能取决于许多因素：通信链接的速度、消息服务器的处理速度和客户机的处理速度，以及其他众多方面。

> 在任何情况下，性能都有几个不同方面。哪些方面对您最重要？这通常要取决于特定应用程序的要求。

> ### 基准检验

> 基准检验是为消息传送应用程序创建测试套件，并针对此测试套件衡量消息吞吐量或其他性能方面的一种过程。

> 例如，您可以创建这样一个测试套件：一定数量的生成方客户机使用一定数量的连接、会话和消息生成器，将标准大小的持久性或非持久性消息按照某个特定速率发送至队列或主题（这完全取决于消息传送应用程序的设计）。同样，测试套件中还包括一定数量的使用方客户机，它们使用一定数量的连接、会话和特定类型的消息使用器（通过特定的确认模式来使用测试套件的目标中的消息）。

> 使用标准的测试套件可以衡量消息的生成和使用之间所花的时间或者消息的平均吞吐速率，您还可以监视系统以观察连接线程使用情况、消息存储数据、消息流数据以及其他相关度量依据。这样就可以提高消息的生成速率、消息生成方的数量或者其他变量，直到性能受到负面影响为止。可能达到的最大吞吐量就是消息服务配置的基准。

> 使用此基准可以修改测试套件的某些特征。控制所有可能影响性能的因素时请小心（请参见“影响性能的应用程序设计因素”），您可以记录这些因素导致基准发生了哪些变化。例如，您可以将连接数或消息大小增加五倍或十倍，并记下对性能产生的影响。

> 相反，您也可以将基于应用程序的因素保持不变，而以某种控制方式更改代理配置（例如，更改连接属性、线程池属性、JVM 内存限制、限制行为、内置与插入的持久性等），并记下这些更改如何影响性能。

> 当您需要通过调整消息服务来增加所部署的应用程序的性能时，这种应用程序基准检验可以提供非常有价值的信息。基准检验可用于更准确地预测所作的更改或一系列更改产生的影响。

> 通常，基准检验应该在受控制的测试环境下运行，并且运行足够长的时间，以使消息服务能够稳定。（性能在启动时会受到实时编译的负面影响，因为要将 Java 代码转换为机器代码。）

> ### 基线使用模式

> 部署并运行消息传送应用程序后，建立基线使用模式是很重要的。您需要知道何时发生峰值需求，并且需要能够量化该需求。例如，需求通常会随最终用户的数量、活动级别、一天当中的时间，或者以上所有这些因素而发生波动。

> 要建立基线使用模式，您需要在一段较长的时间内监视消息服务器，并查看下列数据：连接数、存储在代理（或特定目标）中的消息数、流入和流出代理（或特定目标）的消息，以及活动的用户数目等等。还可以使用度量依据数据中提供的平均值和峰值。

> 将这些基线度量依据数据与设计时的期望值进行比较是非常重要的。通过执行此操作，可以检查客户机代码是否运转正常：例如，检查连接是否未保持打开或者已使用的消息是否仍然保留在未确认状态。这些编码错误会消耗消息服务器资源，并可能极大地影响性能。

> 基线使用模式有助于确定如何调整系统以优化性能。例如，如果某个目标的使用频率明显高于其他目标，那么您可能需要对该目标设置比其他目标更高的内存限制，或者相应地调整限制行为。如果需要的连接数明显大于允许的最大线程池大小，那么可能需要增大线程池的大小，或者采用共享线程模型。如果峰值消息流远远大于平均消息流，这可能影响您在内存不足时采用的限制行为。

> 通常，您对使用模式了解得越多，就能越好地将系统调整为这些模式。并计划将来的需要。

> ##

> 影响性能的因素

> 消息延迟和消息吞吐量是两个主要的性能指示器，它们通常取决于典型消息在完成消息传送过程中的各个步骤时所需的时间。下面步骤显示了如何以持久、可靠的方式传送消息。这些步骤将在插图之后讲述。

> 图 9-1 通过 Message Queue 服务传送消息

> 1. 消息从生成方客户机传送到消息服务器
> 2. 消息服务器读取消息
> 3. 消息被放置到持久性存储器当中（出于可靠性的考虑）
> 4. 消息服务器确认收到消息（出于可靠性的考虑）
> 5. 消息服务器确定消息的路由
> 6. 消息服务器写出消息
> 7. 消息从消息服务器传送到使用方客户机
> 8. 使用方客户机确认收到消息（出于可靠性的考虑）
> 9. 消息服务器处理客户机的确认（出于可靠性的考虑）
> 10. 消息服务器确定已经处理客户机确认

> 由于这些步骤是连续的，所以它们中的任何一个都可能成为消息从生成方客户机到使用方客户机的传送过程中的瓶颈。这些步骤中的大多数都取决于消息传送系统的物理特征：网络带宽、计算机处理速度和消息服务器体系结构等等。但是，有一些步骤还取决于消息传送应用程序的特征和该应用程序要求的可靠性级别。

> 以下各小节讨论应用程序设计因素和消息传送系统因素这二者对性能的影响。尽管应用程序设计和消息传送系统因素在消息的传送过程中交互紧密，但它们彼此是独立的。

> ### 影响性能的应用程序设计因素

> 应用程序的设计决策对消息传送的总体性能有很大影响。

> 对性能影响最大的主要是那些影响消息传送的可靠性因素。包括下列因素：

> - 传送模式（持久性/非持久性消息）
> - 使用事务
> - 确认模式
> - 长期与非长期订阅

> 其他影响性能的应用程序设计因素有：

> - 使用选择器（消息过滤）
> - 消息大小
> - 消息主体类型

> 接下来的几节讲述这些因素当中的每一个对消息传送性能所产生的影响。通常，性能和可靠性应该折衷。增加可靠性的因素可能会导致性能降低。

> 下表显示各个应用程序设计因素大体上如何影响消息传送性能。该表显示了两个方案（一个高可靠性、低性能方案和一个高性能、低可靠性方案）和分别相应于这两个方案的应用程序设计因素选项。在这两种极端情况之间，有很多可以同时影响可靠性和性能的选项和折衷。

> 表 9-1 高可靠性和高性能方案比较

> 应用程序设计因素 | 高可靠性低性能方案 | 高性能低可靠性方案
> --- | --- | ---
> 传送模式 | 持久性消息 | 非持久性消息
> 使用事务 | 事务会话 | 非事务
> 确认模式 | AUTO_ACKNOWLEDGE 或 CLIENT_ACKNOWLEDGE | DUPS_OK_ACKNOWLEDGE
> 长期/非长期订阅 | 长期订阅 | 非长期订阅
> 使用选择器 | 消息过滤 | 无消息过滤
> 消息大小 | 小消息 | 大消息
> 消息主体类型 | 复杂主体类型 | 简单主体类型

> 注意 | 在接下来的图中，性能数据是在一个使用基于文件的持久性双 CPU、1002 Mhz Solaris 8 系统上生成的。性能测试首先预热 Message Queue 代理，使实时编译器优化系统，并启动持久性数据库。 代理预热后，会创建单个生成方和单个使用方，并在 30 秒钟内生成消息。系统将记录使用方接收所有生成的消息所需的时间，并计算吞吐率（每秒收到的消息数）。对于表 9-1 中所示的不同应用程序设计因素组合，此情形会重复出现。

> #### 传送模式（持久性/非持久性消息）

> 如“可靠消息传送”中所述，持久性消息能够在消息服务器发生故障的情况下保证消息的传送。代理会把消息存储在持久性存储库中，直到所有预期的使用方都确认已使用消息为止。

> 通过代理处理持久性消息比处理非持久性消息要慢，理由如下：

> - 代理必须可靠地存储持久性消息，以使其即使在代理出现故障时也不会丢失。
> - 代理必须确认它所收到的每一条持久性消息。如果生成消息的方法返回时没有异常，则对代理的传送即已确保成功。
> - 根据客户机确认模式的不同，代理可能需要确认使用方客户机对持久性消息的确认。

> 持久性和非持久性模式的性能之间可以有很大的差别。图 9-2 比较了在两种可靠的传送情况下持久性和非持久性消息的吞吐量：同时将 10k 大小的消息传送至队列和长期订阅的主题。两种情况下都使用 AUTO_ACKNOWLEDGE 确认模式。

> 图 9-2 传送模式的性能影响

> #### 使用事务

> 事务是一种保证，保证在事务会话中生成和使用的所有消息将作为一个单元进行处理或不进行处理（回滚）。

> Message Queue 同时支持本地和分布式事务（有关详细信息，请分别参见“本地事务”和“分布式事务”）。

> 消息在事务会话中生成或确认时比在非事务会话中要慢，理由如下：

> - 其他信息必须随每个生成的消息存储。
> - 在某些情况下，事务中通常不该存储的消息也存储了（例如，传送至没有订阅的主题目标的持久性消息通常应该删除，但在事务开始时，却没有关于订阅方面的信息）。
> - 提交事务时，该事务中有关消息的使用和确认的信息必须存储并处理。

> #### 确认模式

> 确保可靠传送 JMS 消息的一种机制是，客户机确认使用了由 Message Queue 消息服务器传送给它的消息（请参见“可靠传送：确认和事务”）。

> 如果在客户机尚未确认消息之前就关闭了会话，或者如果消息服务器在处理确认之前发生了故障，代理将重新传送该消息，并设置一个 JMSRedelivered 标志。

> 对于非事务会话，客户机可以选择三种确认模式之一，这三种模式有其各自的性能特征：

> - AUTO_ACKNOWLEDGE。使用方处理消息后，系统会自动确认该消息。此模式可确保在提供者发生故障后至少重新传送一次消息。
> - CLIENT_ACKNOWLEDGE。应用程序控制确认消息的时间点。该会话中自上次确认以来处理的所有消息都将被确认。如果消息服务器在处理一组确认时发生故障，则该组中的一个或多个消息将被重新传送。
> - DUPS_OK_ACKNOWLEDGE。此模式指示系统以一种惰性方式确认消息。在提供者发生故障后，可以重新传送多条消息。

> （CLIENT_ACKNOWLEDGE 模式的用法与事务的用法类似，不同之处在于：它不能保证当提供者在处理过程中发生故障时，所有确认都将一起处理）。

> 确认模式可以影响性能的理由如下：

> - AUTO_ACKNOWLEDGE 和 CLIENT_ACKNOWLEDGE 模式需要在代理和客户机之间有额外的控制消息。附加的控制消息会添加额外的处理开销，并干扰 JMS 有效负荷消息，从而导致处理延迟。
> - 在 AUTO_ACKNOWLEDGE 和 CLIENT_ACKNOWLEDGE 模式中，客户机必须等到代理确认它已处理客户机的确认后，才能使用其他消息。（这种代理确认可确保代理不会无意地重新传送这些消息。）
> - Message Queue 持久性存储库必须采用使用方收到的所有持久性消息的确认信息进行更新，因而降低了性能。

> #### 长期与非长期订阅

> 主题目标的订阅者可以归为两类，即长期订阅和非长期订阅的订阅者，如“发布/订阅（主题目标）”中所述：

> 长期订阅的可靠性较高，但代价是吞吐较慢，原因如下：

> - Message Queue 消息服务器必须永久地存储指定给每个长期订阅的消息的列表，因此如果消息服务器发生故障，该列表只有在恢复之后才可用。
> - 长期订阅的持久性消息是永久存储的，因此如果消息服务器发生故障，消息仍可以在恢复后传送（只要相应的使用方处于活动状态）。与此相反，非长期订阅的持久性消息不是永久存储的（如果消息服务器发生故障，相应的使用方的连接就会断开，消息不再被传送）。

> 图 9-3 比较了两种情况下的长期订阅和非长期订阅主题目标的吞吐量：10K 大小的持久性和非持久性消息。两种情况下都使用 AUTO_ACKNOWLEDGE 确认模式。

> 从图 9-3 中可以看到只有在持久性消息情况下，使用长期订阅的性能影响才会很明显，出现这种影响是因为持久性消息只有在长期订阅时才会永久存储，如上文所述。

> 图 9-3 订阅类型的性能影响

> #### 使用选择器（消息过滤）

> 应用程序的开发者常常需要将消息组的目标定为特定使用方。实现此愿望的方法有两种：将每组消息分别指向唯一的目标；或者是仅使用单个目标，并为每个使用方注册一个或多个选择器。

> 选择器是一种只请求特定消息的字符串，这些消息的属性值（请参见“JMS 消息结构”）应该与传送到特定使用方的字符串匹配。例如，选择器 NumberOfOrders 1 仅传送 NumberOfOrders 属性值为 2 或更大值的消息。

> 将使用方注册到选择器会降低性能（与使用多个目标相比），因为会需要进行额外的处理，以处理每个消息。如果使用选择器，则必须对它进行解析，以使它与将来的消息匹配。另外，路由每个消息时，都必须检索该消息的属性，并与选择器相比较。但是，使用选择器为消息传送应用程序提供了更大的灵活性。

> #### 消息大小

> 消息大小会影响性能是因为从生成方客户机到代理以及从代理到使用方客户机之间必须传递更多的数据，并且对于持久性消息，必须存储更大的消息。

> 但是，通过将较小的消息成批地变为一个消息，对各个消息的路由和处理就可以变得尽可能地简单，从而获得总体性能的提高。此时，就会丢失有关各个消息的状态的信息。

> 图 9-4 比较了在两种情况下，1k、10k 和 100k 大小的消息的吞吐量（KB/秒）：持久性和非持久性消息。每种情况都将消息发送至队列目标，并使用 AUTO_ACKNOWLEDGE 确认模式。

> 图 9-4 显示在这两种情况下，传送较大消息的开销都比传送较小消息时要少。您还可以看到在 1k 和 10k 大小的消息上出现的情况：非持久性消息较持久性消息接近 50% 的性能提高在 100k 大小的消息上并未得到体现，可能是因为在这种情况下，网络带宽已经成为消息吞吐量的瓶颈。

> 图 9-4 消息大小的性能影响

> #### 消息主体类型

> JMS 支持五种消息主体类型，按照复杂性顺序大致显示如下：

> - BytesMessage：按照应用程序所确定的格式包含一组字节
> - TextMessage：一种简单的 java.lang.String
> - StreamMessage：包含 Java 基元值流
> - MapMessage：包含一组名-值对
> - ObjectMessage：包含 Java 序列化对象

> 尽管通常情况下消息类型是由应用程序的需要所决定的，但较复杂的类型（MapMessage 和 ObjectMessage）会增加性能成本 对数据进行序列化和反序列化的成本。性能成本取决于数据的简单或复杂程度。

> ### 影响性能的消息服务因素

> 消息传送应用程序的性能不但受应用程序设计的影响，而且还受执行消息路由和传送的消息服务的影响。

> 以下各节讨论影响性能的各个消息服务因素。了解这些因素的影响对于评估消息服务以及诊断并解决在部署的应用程序中可能发生的性能瓶颈来说至关重要。

> Message Queue 服务中影响性能的最重要的因素有：

> - 硬件
> - 操作系统
> - Java 虚拟机 (JVM)
> - 连接
> - 代理限制和行为
> - 消息服务器体系结构
> - 数据存储性能
> - 客户机运行时配置

> 以下各节讲述这些因素中的每一个对消息传送性能所产生的影响。

> #### 硬件

> 对于 Message Queue 消息服务器和客户机应用程序而言，CPU 处理速度和可用内存都是消息服务性能的主要决定因素。大多数软件限制都可以通过增加处理能力来消除，而添加内存则可以同时提高处理速度和容量。但是，仅通过升级硬件来克服瓶颈通常过于昂贵。

> #### 操作系统

> 由于不同操作系统的效率不同，所以即使硬件平台相同，性能也会各不相同。例如，操作系统使用的线程模型会对消息服务器可以支持的并行连接数产生重要影响。在所有硬件都相同的情况下，Solaris 通常比 Linux 快，而后者通常又比 Windows 快。

> #### Java 虚拟机 (JVM)

> 消息服务器是受主机 JVM 支持并运行在其中的一种 Java 进程。因此，JVM 处理是决定消息服务器路由和传送消息的速度和效率的重要因素。

> 特别是 JVM 的内存资源管理至关重要。必须为 JVM 分配足够的内存以满足不断增大的内存负荷。另外，JVM 将定期地释放未使用的内存，而这种内存释放会延迟消息的处理。JVM 内存堆越大，内存释放过程中可能遇到的延迟就越长。

> #### 连接

> 客户机和代理之间的连接数目和速度可能影响消息服务器可以处理的消息数以及消息的传送速度。

> ##### 消息服务器连接限制

> 对消息服务器的所有访问都是通过连接的方式进行的。对并行连接数的任何限制都会影响可以同时使用消息服务器的生成方或使用方客户机的数目。

> 消息服务器的连接数通常由可用的线程数限制。Message Queue 使用了线程池管理器，您可以将其配置为支持专用线程模型或共享线程模型（请参见“线程池管理器”）。专用线程模型的速度非常快，因为每个连接都有专用的线程，但是连接数目受可用线程数的限制（每个连接都有一个输入线程和一个输出线程）。共享线程模型对连接数不加任何限制，但是在大量连接之间共享线程时会有明显的开销和吞吐量延迟，特别是当这些连接都很繁忙时。

> ##### 传输协议

> Message Queue 软件允许客户机使用各种低级别的传输协议与消息服务器进行通信。Message Queue 支持“连接服务支持”中所示的连接服务（及相应协议）。协议的选择基于应用程序的要求（加密、通过防火墙访问等），但是所作的选择会影响总体性能。

> 图 9-5 传输协议速度

> 图 9-5 反映不同协议技术的性能特征：

> - TCP 提供与代理通信的最快方法。
> - SSL 在收发消息时比 TCP 要慢 50％ 到 70％（对于持久性消息是 50％，对于非持久性消息则接近 70％）。另外，SSL 在建立初始连接时比较慢（可能需要数秒钟），因为客户机和代理（在使用 HTTPS 时为 Web 服务器）需要建立专用密钥，以供加密数据以进行传输时使用。性能的下降源自于加密和解密每个低级别 TCP 数据包时所需的额外处理。

> 图 9-6 比较了两种情况下的 TCP 和 SSL 吞吐量：一个高可靠性方案（将 1k 大小的持久性消息发送至长期订阅主题目标，并使用 AUTO_ACKNOWLEDGE 确认模式）和一个高性能方案（将 1k 大小的非持久性消息发送至非长期订阅主题目标，并使用 DUPS_OK_ACKNOWLEDGE 确认模式）。

> 图 9-6 显示了在高可靠性情况下产生较小影响的协议。这可能是因为在高可靠性情况下所需的持久性开销在限制吞吐量方面是比协议速度更重要的因素。

> 图 9-6 传输协议的性能影响

> - HTTP 比 TCP 或 SSL 都要慢。它使用 servlet，该 servlet 在 Web 服务器上作为客户机和代理之间的代理服务器运行。性能开销涉及封装 HTTP 请求中的数据包，并涉及消息要经过两个跃点（客户机到 servlet，servlet 到代理）后才到达代理这一要求。
> - HTTPS 比 HTTP 要慢是因为需要额外的开销以加密客户机和 servlet 之间以及 servlet 和代理之间的数据包。

> #### 消息服务器体系结构

> Message Queue 消息服务器可以作为单个代理实现，也可以作为多个互相连接的代理实例（即代理群集）实现。

> 随着连接到代理的客户机数量以及所传送的消息数量的不断增加，代理最终将超出资源限制（例如文件描述符、线程和内存限制）。适应不断增加的负荷的方法之一是将更多的代理实例添加到 Message Queue 消息服务器，从而将客户机连接以及消息路由和传送分布到多个代理。

> 通常，如果客户机（特别是消息生成方客户机）均匀地分布在群集中，则这种调整最为有效。由于在群集的代理之间传送消息会涉及到开销，因此连接数有限或消息传送速率有限的群集，其性能可能会比单个代理要低。

> 您也可以使用代理群集来优化网络带宽。例如，您可能希望在群集内的一组远程代理之间使用低速的长途网络链路，而在客户机与其各自的代理实例之间使用高速链接进行连接。

> 有关群集的详细信息，请参见“多代理群集（企业版）”和“使用群集（企业版）”。

> #### 代理限制和行为

> 消息服务器可能需要处理的消息吞吐量是消息服务器所支持的消息传送应用程序的使用模式的一项功能。但是，消息服务器在资源方面有限：内存、CPU 周期等。因此，在消息服务器变得无响应或不稳定的位置，它可能会崩溃。

> Message Queue 消息服务器具有管理内存资源并防止代理用尽内存的内置机制。这些机制包括可配置的消息数限制，或代理可以拥有的消息字节数或其各自的目标，以及当达到目标限制时可以实施的一组行为（请参见“管理内存资源和消息流”）。

> 通过仔细地监视和调整，这些可配置机制可以用于平衡消息的内流和外流，以使系统过载不会发生。尽管这些机制会造成开销并限制消息的吞吐量，但它们可以维护操作的完成性。

> #### 数据存储性能

> Message Queue 既支持内置的持久性，也支持插入的持久性（请参见“持久性管理器”）。内置的持久性是基于文件的数据存储。插入的持久性使用 Java 数据库连接 (JDBC) 接口，并需要 JDBC 兼容的数据存储。

> 内置的持久性明显比插入的持久性要快，但是 JDBC 兼容的数据库系统可以提供应用程序需要的冗余、安全性和管理功能。

> 如果是内置持久性，您可以通过指定让持久性操作将内存中状态与数据存储同步，从而将可靠性增至最大。这有助于消除因系统崩溃而导致的数据丢失，但代价是性能的下降。

> #### 客户机运行时配置

> Message Queue 客户机运行时可提供客户机应用程序及其与 Message Queue 消息服务的接口。它支持客户机向目标发送消息以及接收来自这些目标的消息所需的所有操作。客户机运行时是可配置的（通过设置连接工厂属性值），使您可以设置通常能够提高性能和消息吞吐量的属性和行为。

> 例如，Message Queue 客户机运行时支持下列可配置行为：

> - 连接流测量 (imqConnectionFlowCount)，此行为有助于防止由于 JMS 消息和 Message Queue 控制消息通过同一连接时所形成的流引起的拥塞。
> - 连接流限制 (imqConnectionFlowLimit)，此行为有助于通过限制等待使用的、可以通过连接传送到客户机运行时的消息数，来避免客户机的资源限制。
> - 用户流限制 (imqConsumerFlowLimit)，此行为有助于改进在多用户队列传送情况下用户之间的负荷平衡（因此向任何一个用户发送的消息数都是均衡的），并有助于阻止连接上的任何一个用户影响连接上的其他用户。此属性可以限制每个用户等待使用的、可以通过连接传送到客户机运行时的消息数。还可以将该属性配置为队列目标属性 (consumerFlowLimit)。

> 有关这些行为和用来配置这些行为的属性的详细信息，请参见“客户机运行时消息流调整”。

> ##

> 监视消息服务器

> Message Queue 服务器经配置后可以提供能够用于监视其性能的度量依据信息。本节描述可以用于监视消息服务器的各种工具以及能够使用这些工具获得的度量依据数据。

> 有关如何使用度量依据数据来解决性能问题或者分析和调整消息服务器性能的信息，请参见“性能问题疑难解答”。

> ### 监视工具

> 可以使用下列工具获得度量依据信息：

> - Message Queue 命令行实用程序 (imqcmd)
> - Message Queue 代理日志文件
> - 基于消息的监视 API

> 以下各节描述如何使用这些工具中的每一种以获得度量依据信息。有关不同工具之间的比较，请参见“选择适当的监视工具”。

> #### Message Queue 命令行实用程序 (imqcmd)

> 命令行实用程序 (imqcmd) 是 Message Queue 的基本命令行管理工具。通过它可以管理代理及其连接服务，以及应用程序特有的资源，例如物理目标、长期订阅和事务。imqcmd 命令在第 6 章“代理和应用程序管理”中有所说明

> imqcmd 命令的功能之一是它为作为一个整体的代理、为单个的连接服务以及为单个的目标获得度量依据信息的能力。要获得度量依据数据，通常应该使用 imqcmd 的 metrics 子命令。度量依据数据将按照您指定的时间间隔或者次数写到控制台屏幕上。

> 您也可以使用 query 子命令（请参见"imqcmd query"）获得度量依据数据的更具体的子集。

> ##### imqcmd metrics

> imqcmd metrics 的语法和选项分别如表 9-2 和表 9-3所示。

> 表 9-2 imqcmd metrics 子命令语法

> 子命令语法 | 提供的度量依据数据
> --- | ---
> metrics bkr [-b hostName:port] [-m metricType] [-int interval] [-msp numSamples] [-u userName [-p pasword | 显示默认代理的代理度量依据，或显示指定主机和端口上的代理的代理度量依据。
> 或 |
> metrics svc -n serviceName [-b hostName:port] [-m metricType] [-int interval] [-msp numSamples] [-u userName [-p pasword | 显示默认代理或指定主机和端口上的代理中指定服务的度量依据。
> 或 |
> metrics dst -t destType -n destName [-b hostName:port] [-m metricType] [-int interval] [-msp numSamples] [-u userName [-p pasword | 显示指定类型和名称的目标的度量依据信息。

> 表 9-3 imqcmd metrics 子命令选项

> 子命令选项 | 说明
> --- | ---
> -b hostName:port | 指定度量依据数据所报告的代理的主机名和端口。默认为 localhost:7676
> -int interval | 指定显示度量依据的时间间隔（以秒为单位）。默认值为 5 秒。
> -m metricType | 指定要显示的度量依据类型。 ttl 显示流入和流出代理的消息和数据包的度量依据（默认度量依据类型） rts 显示消息和数据包流入和流出代理的速率（每秒）的度量依据 cxn 显示连接、虚拟内存堆和线程（仅适用于代理和连接服务） con 显示与用户相关的度量依据（仅适用于目标） dsk 显示磁盘使用情况度量依据（仅适用于目标）
> -msp numSamples | 指定输出中显示的样例数。默认值为无限数（无穷大）。
> -n destName | 指定度量依据数据要报告的目标（如果有）的名称。没有默认值。
> -n serviceName | 指定度量依据数据要报告的连接服务（如果有）。没有默认值。
> -t destTyp | 指定度量依据数据要报告的目标（如果有）的类型（队列或主题）。没有默认值。
> -u userName | 指定您（管理员）的名称。如果省略此值，系统会提示您输入。
> -p password | 指定您（管理员）的密码。如果省略此值，系统会提示您输入。

> ##### 过程：使用 metrics 子命令显示度量依据数据

> 本节讲述使用 metrics 子命令报告度量依据信息的过程。

> ##### 要使用 metrics 子命令，请执行下列操作：

> 1. 启动度量依据信息需要的代理。

> 请参见“启动代理”。

> 2. 发出相应的 imqcmd metrics 子命令和选项，如表 9-2 和表 9-3 中所示。

> ##### 度量依据输出：imqcmd metrics

> 本节显示代理范围、连接服务和目标度量依据的 metrics 子命令输出示例。

> 代理范围度量依据。 要获取在 10 秒的时间间隔内流入和流出代理的消息和数据包的速率，请使用 metrics bkr 子命令：

> imqcmd metrics bkr -m rts -int 10 -u admin -p admin

> 此命令产生的输出结果类似如下内容（请参见表 9-8 中的数据说明）：

> --------------------------------------------------------
> Msgs/sec Msg Bytes/sec Pkts/sec Pkt Bytes/sec
> In Out In Out In Out In Out
> --------------------------------------------------------
> 0 0 27 56 0 0 38 66
> 10 0 7365 56 10 10 7457 1132
> 0 0 27 56 0 0 38 73
> 0 10 27 7402 10 20 1400 8459
> 0 0 27 56 0 0 38 73

> 连接服务度量依据。 要获取 jms 连接服务所处理的消息和数据包的累计总数，请使用 metrics svc 子命令：

> imqcmd metrics svc -n jms -m ttl -u admin -p admin

> 此命令产生的输出结果类似如下内容（请参见表 9-9 中的数据说明）：

> -------------------------------------------------
> Msgs Msg Bytes Pkts Pkt Bytes
> In Out In Out In Out In Out
> -------------------------------------------------
> 164 100 120704 73600 282 383 135967 102127
> 657 100 483552 73600 775 876 498815 149948

> 目标度量依据。 要获取有关目标的度量依据信息，请使用 metricsdst 子命令：

> imqcmd metrics dst -t q -n XQueue -m ttl -u admin -p admin

> 此命令产生的输出结果类似如下内容（请参见表 9-10 中的数据说明）：

> -----------------------------------------------------------------------------
> Msgs Msg Bytes Msg Count Total Msg Bytes (k) Largest
> In Out In Out Current Peak Avg Current Peak Avg Msg (k)
> -----------------------------------------------------------------------------
> 200 200 147200 147200 0 200 0 0 143 71 0
> 300 200 220800 147200 100 200 10 71 143 64 0
> 300 300 220800 220800 0 200 0 0 143 59 0

> 要获取有关目标的用户的信息，请使用下面的 metricsdst 子命令：

> imqcmd metrics dst -t q -n SimpleQueue -m con -u admin -p admin

> 此命令产生的输出结果类似如下内容（请参见表 9-10 中的数据说明）：

> ------------------------------------------------------------------
> Active Consumers Backup Consumers Msg Count
> Current Peak Avg Current Peak Avg Current Peak Avg
> ------------------------------------------------------------------
> 1 1 0 0 0 0 944 1000 525

> ##### imqcmd query

> imqcmd query 命令的语法和选项如表 9-4 中所示，并带有该命令所提供的度量依据数据的说明。

> 表 9-4 imqcmd query 子命令语法

> 子命令语法 | 提供的度量依据数据
> --- | ---
> query bkr [-b hostName:port] [-int interval] [-msp numSamples] | 有关当前存储在代理内存和持久性存储库中的消息个数和消息字节数目的信息（请参见“显示代理信息”）
> 或 |
> metrics svc -n serviceName [-b hostName:port] [-int interval] [-msp numSamples] | 有关指定的连接服务的当前已分配线程数和连接数的信息（请参见“显示连接服务信息”）
> 或 |
> metrics dst -t destType -n destName [-b hostName:port] [-int interval] [-msp numSamples] | 有关指定目标的当前生成方的数目、活动和备份使用方的数目以及存储在内存和持久性存储库中的消息数和消息字节数的信息（请参见“显示目标信息”）

> 注意 | 由于 imqcmd query 提供的度量依据数据有限，“度量依据数据说明”一节的表中中未提供此工具。

> #### Message Queue 代理日志文件

> Message Queue 日志记录器获取代理代码、调试器和度量依据生成器等生成的信息，并将该信息写到多个输出通道：标准输出（控制台）、日志文件以及 Solaris 平台上的 syslog 守护程序进程。日志记录器在“日志记录器”中有所说明。

> 您可以指定日志记录器所收集的信息类型以及写到每个输出通道的类型。特别地，您可以指定希望将度量依据度量依据信息写入到日志文件。

> ##### 过程：使用代理日志文件报告度量依据数据

> 本节讲述使用代理日志文件报告度量依据信息的过程。有关配置日志记录器的一般信息，请参见“日志记录”。

> ##### 要使用日志文件来报告度量依据信息，请执行下列操作：

> 1. 配置代理的度量依据生成功能：
> 1. 确认 imq.metrics.enabled=true

> 默认情况下，用于日志记录的度量依据生成功能会打开。

> 2. 将度量依据生成时间间隔设置为比较合适的秒数。

> imq.metrics.interval=interval

> 此值可以在 config.properties 文件中设置，或者在启动代理时使用 -metrics interval 命令行选项进行设置。

> 2. 确认日志记录器是否收集度量依据信息：

> imq.log.level=INFO

> 这是默认值。此值可以在 config.properties 文件中设置，或者在启动代理时使用 -loglevel level 命令行选项进行设置。

> 3. 确认日志记录器是否已设置为将度量依据信息写入日志文件：

> imq.log.file.output=INFO

> 这是默认值。它可以在 config.properties 文件中设置。

> 4. 启动代理。

> ##### 度量依据输出：日志文件

> 下面显示了到日志文件的代理度量依据输出样例（请参见表 9-7 和表 9-8 中的度量依据数据说明）：

> [21/Jul/2003:11:21:18 PDT]
> Connections: 0 JVM Heap: 8323072 bytes (7226576 free) Threads: 0 (14-1010)
> In: 0 msgs (0bytes) 0 pkts (0 bytes)
> Out: 0 msgs (0bytes) 0 pkts (0 bytes)
> Rate In: 0 msgs/sec (0 bytes/sec) 0 pkts/sec (0 bytes/sec)
> Rate Out: 0 msgs/sec (0 bytes/sec) 0 pkts/sec (0 bytes/sec)

> #### 基于消息的监视 API

> Message Queue 提供度量依据的监视功能，通过该功能，代理可以将度量依据数据写入到 JMS 消息，然后根据消息中包含的度量依据信息类型将它们发送到众多度量依据主题目标中的某一个目标。

> 您可以通过编写具有下列功能的客户机应用程序来访问此度量依据信息：订阅度量依据主题目标、使用这些目标中的消息以及处理消息中包含的度量依据信息。度量依据中介绍了通用方案。

> 共有五个度量依据主题目标，它们的名称以及传送到各个目标的度量依据消息的类型显示在表 9-5 中。

> 表 9-5 度量依据主题目标

> 主题名称 | 度量依据消息类型
> --- | ---
> mq.metrics.broker | 代理度量依据
> mq.metrics.jvm | Java 虚拟机度量依据
> mq.metrics.destination_list | 目标及其类型列表
> mq.metrics.destination.queue. monitoredDestinationName | 具有指定名称的队列的目标度量依据
> mq.metrics.destination.topic. monitoredDestinationName | 具有指定名称的主题的目标度量依据

> ##### 过程：设置基于消息的监视

> 本节讲述使用基于消息的监视功能来收集度量依据信息的过程。该过程包括客户机开发和管理任务这两方面。

> ##### 要设置基于消息的监视，请执行下列操作：

> 1. 编写度量依据监视客户机。

> 有关以编程方式编写订阅度量依据主题目标、使用度量依据消息并从这些消息中提取度量依据数据的客户机的说明，请参见《Message Queue Java Client Developer's Guide》。

> 2. 通过在 config.properties 文件中设置代理属性来配置代理的度量依据消息生成方：
> 1. 启用度量依据消息生成。

> 设置 imq.metrics.topic.enabled=true

> 默认值为 true。

> 2. 设置生成度量依据消息的时间间隔（以秒为单位）。

> 设置 imq.metrics.topic.interval=interval

> 默认值为 60 秒。

> 3. 指定是否需要让度量依据消息成为持久性的消息（即，当代理发生故障时它们是否还能保留）。

> 设置 imq.metrics.topic.persist

> 默认值为 false。

> 4. 指定在删除度量依据消息之前它们能在各自的目标中保留的时间。

> 设置 imq.metrics.topic.timetolive

> 默认值为 300 秒。

> 3. 设置需要对度量依据主题目标设置的任何访问控制。

> 请参见下面的“安全性和访问注意事项”中的讨论。

> 4. 启动度量依据监视客户机。

> 当用户订阅度量依据主题时，系统就会自动创建度量依据主题目标。创建度量依据主题后，代理的度量依据消息生成方就会开始向度量依据主题发送度量依据消息。

> ##### 安全性和访问注意事项

> 出于以下两个原因，需要限制对主题目标的访问：

> - 度量依据数据可能包含有关代理及其资源的敏感信息
> - 对度量依据主题目标的过多订阅可能会增大代理开销，从而给性能带来负面影响

> 出于这些方面的考虑，建议限制对度量依据主题目标的访问。

> 监视客户机的验证和授权控制与其他任何客户机都相同。只有保持在 Message Queue 用户信息库中的用户才允许连接代理。

> 您可以通过某个访问控制属性文件，限制对特定度量依据主题目标的访问，从而提供其他保护，如“授权用户： 访问控制属性文件”中所述。

> 例如，accesscontrol.properties 文件中的下列条目将拒绝除用户 1 和用户 2 之外的其他所有用户对 mq.metrics.broker 度量依据主题的访问。

> topic.mq.metrics.broker.consume.deny.user=* topic.mq.metrics.broker.consume.allow.user=user1,user2

> 下列条目将仅允许用户 user3 监视主题 t1。

> topic.mq.metrics.destination.topic.t1.consume.deny.user=* topic.mq.metrics.destination.topic.t1.consume.allow.user=user3

> 根据度量依据数据的敏感度不同，您也可以使用加密连接将度量依据监视客户机连接至代理。有关使用加密连接的信息，请参见“加密：使用基于 SSL 的服务（企业版）”。

> ##### 度量依据输出：度量依据消息

> 使用基于消息的监视 API 获得的度量依据数据输出是您编写的度量依据监视客户机的一个函数。您只会受到代理中度量依据生成器提供的数据的限制。有关此数据的完整列表，请参见“度量依据数据说明”。

> #### 选择适当的监视工具

> 前面各节中讨论的每种监视工具都各有其优缺点。

> 例如，使用 imqcmd metrics 命令可以在您需要时迅速地抽取适合您需要的信息，但这会造成查看历史信息或者以编程方式操纵数据变得有些困难。

> 另一方面，日志文件可以提供度量依据数据的长期记录，但是日志文件中的信息很难解析为有意义的信息。

> 基于消息的监视 API 可用于轻松地提取您需要的信息、对其进行处理、以编程方式操纵或格式化数据以及提供图形或发送警报；但是您必须编写自定义应用程序以捕获并分析数据。

> 另外，这些工具中的每一种所收集到的由代理生成的度量依据信息的子集会稍有不同。有关哪些度量依据数据是由何种监视工具收集的信息，请参见“度量依据数据说明”。

> 表 9-6 从每种工具的正反两面对这些工具进行了比较。

> 表 9-6 度量依据监视工具的正面和反面因素

> 度量依据监视工具 | 正面因素 | 反面因素
> --- | --- | ---
> imqcmd metrics | 远程监视 便于抽样检查 在命令选项中设置报告的时间间隔，可以随时更改 易于选择感兴趣的特定数据 数据以简易的表格格式提供 | 单条命令无法获取所有数据 难于以编程方式分析数据 不能创建历史记录 难于看到历史趋势
> 日志文件 | 定期采样 创建历史记录 | 需要配置代理属性；必须关闭并重新启动代理才能生效 仅限本地监视 数据格式非常难于读取或解析；没有解析工具 报告时间间隔不能随时更改；所有度量依据数据也是如此 在数据的选择上不能提供灵活性 仅限代理度量依据；目标和连接服务度量依据不包括在内 如果时间间隔过短，性能可能会受影响
> 基于消息的监视 API | 远程监视 易于选择感兴趣的特定数据 数据可以按照电子格式分析，并能够以任何格式提供 | 需要配置代理属性；必须关闭并重新启动代理才能生效 需要编写您自己的度量依据监视客户机 报告时间间隔不能随时更改；所有度量依据数据也是如此

> ### 度量依据数据说明

> 代理所报告的度量依据信息可以归为下列几类：

> - Java 虚拟机 (JVM) 度量依据。有关 JVM 堆大小的信息。
> - 代理范围度量依据。有关存储在代理中的消息的信息以及有关流入和流出代理的消息的信息，这两种信息都以消息数和字节数表示（包括绝对数量和速率）。此类别还包括有关内存使用情况的信息。
> - 连接服务度量依据。有关连接和连接线程资源的信息，以及有关特定连接服务的消息流的信息。
> - 目标度量依据。有关流入和流出特定目标的消息的信息、有关目标的使用方的消息以及有关内存和磁盘空间使用情况的信息。

> 以下各节讲述每个类别中的可用度量依据数据。有关下列各表中提到的监视工具的信息，请参见“监视工具”。

> #### JVM 度量依据

> 表 9-7 列出并说明了代理为代理进程 JVM 堆生成的度量依据数据，并显示了使用不同的度量依据监视工具可以获得哪些数据。

> 表 9-7 JVM 度量依据

> 度量依据数量 | 说明 | imqcmd metrics bkr(metricType) | 日志文件 | 度量依据消息（metrics topic)1
> --- | --- | --- | --- | ---
> JVM 堆：可用内存 | 可用于 JVM 堆的内存量 | 是 (cxn) | 是 | 是(…jvm)
> JVM 堆：总内存 | 当前的 JVM 堆大小 | 是 (cxn) | 是 | 是(…jvm)
> JVM 堆：最大内存 | JVM 堆可以达到的最大大小。 | 否 | 是2 | 是(…jvm)

> 1有关度量依据主题目标的名称，请参见表 9-5。 2仅在代理启动时显示。

> #### 代理范围度量依据

> 表 9-8 列出并说明了代理所报告的有关代理范围内的度量依据信息的数据。它还显示了哪些数据可以使用不同的度量依据监视工具获得。

> 表 9-8 代理范围度量依据

> 度量依据数量 | 说明 | imqcmd metrics bkr（metricType) | 日志文件 | 度量依据消息（metrics topic)1
> --- | --- | --- | --- | ---
> 连接数据
> Num connections | 当前对代理打开的连接数 | 是 (cxn) | 是 | 是(…broker)
> Num threads | 当前使用的线程数 | 是 (cxn) | 是 | 否
> Min threads | 特定的线程数，达到该数量后，线程池中将维护此数量的线程供连接服务使用 | 是 (cxn) | 是 | 否
> Max threads | 特定的线程数，达到该数量后，线程池中将不会添加新的线程以供连接服务使用 | 是 (cxn) | 是 | 否
> 存储消息数据
> Num messages | 当前存储在代理内存和持久性存储库中的 JMS 消息数 | 否使用 query bkr | 否 | 是(…broker)
> Total message bytes | 当前存储在代理内存和持久性存储库中的 JMS 消息字节数 | 否使用 query bkr | 否 | 是(…broker)
> 消息流数据
> Num messages in | 自从代理上次启动以来流入该代理的 JMS 消息数 | 是 (ttl) | 是 | 是(…broker)
> Message bytes in | 自从代理上次启动以来流入该代理的 JMS 消息字节数 | 是 (ttl) | 是 | 是(…broker)
> Num packets in | 自从代理上次启动以来流入该代理的数据包（包括 JMS 消息和控制消息）数 | 是 (ttl) | 是 | 是(…broker)
> Packet bytes in | 自从代理上次启动以来流入该代理的数据包（包括 JMS 消息和控制消息）字节数 | 是 (ttl) | 是 | 是(…broker)
> Num messages out | 自从代理上次启动以来流出该代理的 JMS 消息数 | 是 (ttl) | 是 | 是(…broker)
> Message bytes out | 自从代理上次启动以来流出该代理的 JMS 消息字节数 | 是 (ttl) | 是 | 是(…broker)
> Num packets out | 自从代理上次启动以来流出该代理的数据包（包括 JMS 消息和控制消息）数 | 是 (ttl) | 是 | 是(…broker)
> Packet bytes out | 自从代理上次启动以来流出该代理的数据包（包括 JMS 消息和控制消息）字节数 | 是 (ttl) | 是 | 是(…broker)
> Rate messages in | JMS 消息流入代理的当前速率 | 是 (rts) | 是 | 否
> Rate message bytes in | JMS 消息字节流入代理的当前速率 | 是 (rts) | 是 | 否
> Rate packets in | 数据包（包括 JMS 消息和控制消息）流入代理的当前速率 | 是 (rts) | 是 | 否
> Rate packet bytes in | 数据包（包括 JMS 消息和控制消息）字节流入代理的当前速率 | 是 (rts) | 是 | 否
> Rate messages out | JMS 消息流出代理的当前速率 | 是 (rts) | 是 | 否
> Rate message bytes out | JMS 消息字节流出代理的当前速率 | 是 (rts) | 是 | 否
> Rate packets out | 数据包（包括 JMS 消息和控制消息）流出代理的当前速率 | 是 (rts) | 是 | 否
> Rate packet bytes out | 数据包（包括 JMS 消息和控制消息）字节流出代理的当前速率 | 是 (rts) | 是 | 否
> 目标数据
> Num destinations | 代理中的物理目标数 | 否 | 否 | 是(…broker)

> 1有关度量依据主题目标的名称，请参见表 9-5。

> #### 连接服务度量依据

> 表 9-9 列出并说明了代理为各个连接服务所报告的度量依据数据。它还显示了哪些数据可以使用不同的度量依据监视工具获得。

> 表 9-9 连接服务度量依据

> 度量依据数量 | 说明 | imqcmd metrics svc（metricType) | 日志文件 | 度量依据消息（metrics topic)
> --- | --- | --- | --- | ---
> 连接数据
> Num connections | 当前打开的连接数 | 是 (cxn) 还有 query svc | 否 | 否
> Num threads | 所有连接服务当前总计使用的线程数 | 是 (cxn) 还有 query svc | 否 | 否
> Min threads | 特定的供所有连接服务使用的总计线程数，达到该数量后，线程池中将维护此数量的线程供连接服务使用 | 是 (cxn) | 否 | 否
> Max threads | 特定的供所有连接服务使用的总计线程数，达到该数量后，线程池中将不会添加新的线程以供连接服务使用 | 是 (cxn) | 否 | 否
> 消息流数据
> Num messages in | 自从代理上次启动以来流入连接服务的 JMS 消息数 | 是 (ttl) | 否 | 否
> Message bytes in | 自从代理上次启动以来流入连接服务的 JMS 消息字节数 | 是 (ttl) | 否 | 否
> Num packets in | 自从代理上次启动以来流入连接服务的数据包（包括 JMS 消息和控制消息）数 | 是 (ttl) | 否 | 否
> Packet bytes in | 自从代理上次启动以来流入连接服务的数据包（包括 JMS 消息和控制消息）字节数 | 是 (ttl) | 否 | 否
> Num messages out | 自从代理上次启动以来流出连接服务的 JMS 消息数 | 是 (ttl) | 否 | 否
> Message bytes out | 自从代理上次启动以来流出连接服务的 JMS 消息字节数 | 是 (ttl) | 否 | 否
> Num packets out | 自从代理上次启动以来流出连接服务的数据包（包括 JMS 消息和控制消息）数 | 是 (ttl) | 否 | 否
> Packet bytes out | 自从代理上次启动以来流出连接服务的数据包（包括 JMS 消息和控制消息）字节数 | 是 (ttl) | 否 | 否
> Rate messages in | JMS 消息通过连接服务流入代理的当前速率。 | 是 (rts) | 否 | 否
> Rate message bytes in | JMS 消息字节流入连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate packets in | 数据包（包括 JMS 消息和控制消息）流入连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate packet bytes in | 数据包（包括 JMS 消息和控制消息）字节流入连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate messages out | JMS 消息流出连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate message bytes out | JMS 消息字节流出连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate packets out | 数据包（包括 JMS 消息和控制消息）流出连接服务的当前速率 | 是 (rts) | 否 | 否
> Rate packet bytes out | 数据包（包括 JMS 消息和控制消息）字节流出连接服务的当前速率 | 是 (rts) | 否 | 否

> #### 目标度量依据

> 表 9-9 列出并说明了代理为各个目标所报告的度量依据数据。它还显示了哪些数据可以使用不同的度量依据监视工具获得。

> 表 9-10 目标度量依据

> 度量依据数量 | 说明 | imqcmd metrics dst（metricType) | 日志文件 | 度量依据消息（metrics topic)1
> --- | --- | --- | --- | ---
> 使用方数据
> Num active consumers | 当前活动使用方数 | 是 (con) | 否 | 是 (…destName)
> Avg num active consumers | 自从代理上次启动以来的平均活动使用方数 | 是 (con) | 否 | 是 (…destName)
> Peak num active consumers | 自从代理上次启动以来的最大活动使用方数 | 是 (con) | 否 | 是 (…destName)
> Num backup consumers | 当前备份使用方数（仅适用于队列） | 是 (con) | 否 | 是 (…destName)
> Avg num backup consumers | 自从代理上次启动以来的平均备份使用方数（仅适用于队列） | 是 (con) | 否 | 是 (…destName)
> Peak num backup consumers | 自从代理上次启动以来的最大备份使用方数（仅适用于队列） | 是 (con) | 否 | 是 (…destName)
> 存储消息数据
> Num messages | 当前存储在目标内存和持久性存储库中的 JMS 消息数 | 是 (con) (ttl) (rts) 还有 query dst | 否 | 是 (…destName)
> Avg num messages | 自从代理上次启动以来存储在目标内存和持久性存储库中的平均 JMS 消息数 | 是 (con) (ttl) (rts) | 否 | 是 (…destName)
> Peak num messages | 自从代理上次启动以来存储在目标内存和持久性存储库中的最大 JMS 消息数 | 是 (con) (ttl) (rts) | 否 | 是 (…destName)
> Total message bytes | 当前存储在目标内存和持久性存储库中的 JMS 消息字节数 | 是 (ttl) (rts) 还有 query dst | 否 | 是 (…destName)
> Avg total message bytes | 自从代理上次启动以来存储在目标内存和持久性存储库中的平均 JMS 消息字节数 | 是 (ttl) (rts) | 否 | 是 (…destName)
> Peak total message bytes | 自从代理上次启动以来存储在目标内存和持久性存储库中的最大 JMS 消息字节数 | 是 (ttl) (rts) | 否 | 是 (…destName)
> Peak message bytes | 自从代理上次启动以来目标接收到的单个消息中 JMS 消息的最大字节数 | 是 (ttl) (rts) | 否 | 是 (…destName)
> 消息流数据
> Num messages in | 自从代理上次启动以来流入此目标的 JMS 消息数 | 是 (ttl) | 否 | 是 (…destName)
> Msg bytes in | 自从代理上次启动以来流入此目标的 JMS 消息字节数 | 是 (ttl) | 否 | 是 (…destName)
> Num messages out | 自从代理上次启动以来流出此目标的 JMS 消息数 | 是 (ttl) | 否 | 是 (…destName)
> Msg bytes out | 自从代理上次启动以来流出此目标的 JMS 消息字节数 | 是 (ttl) | 否 | 是 (…destName)
> Rate num messages in | JMS 消息流入目标的当前速率 | 是 (rts) | 否 | 否
> Rate num messages out | JMS 消息流出目标的当前速率 | 是 (rts) | 否 | 否
> Rate msg bytes in | JMS 消息字节流入目标的当前速率 | 是 (rts) | 否 | 否
> Rate Msg bytes out | JMS 消息字节流出目标的当前速率 | 是 (rts) | 否 | 否
> 磁盘使用情况数据
> Disk reserved | 基于目标文件的存储库中所有消息记录（活动的和空闲的）使用的磁盘空间（以字节为单位） | 是 (dsk) | 否 | 是 (…destName)
> Disk used | 基于目标文件的存储库中活动消息记录使用的磁盘空间（以字节为单位） | 是 (dsk) | 否 | 是 (…destName)
> Disk utilization ratio | 已用磁盘空间除以保留磁盘空间所得的商。比率越高，用于容纳活动消息时所占用的磁盘空间就越多 | 是 (dsk) | 否 | 是 (…destName)

> 1有关度量依据主题目标的名称，请参见表 9-5。

> ##

> 性能问题疑难解答

> 使用 Message Queue 服务支持应用程序时，可能会发生很多性能问题。这些问题包括：

> - “问题：客户机无法建立连接”
> - “问题：连接的吞吐量太慢”
> - “问题：客户机无法创建消息生成方”
> - “问题：消息的生成过程发生延迟或变慢”
> - “问题：消息在消息服务器中堆积”
> - “问题：消息服务器吞吐量呈间歇性”
> - “问题：消息无法到达使用方”

> 下面会逐个讨论这些问题，并说明这些问题的可能起因及解决方案。

> ### 问题：客户机无法建立连接

> #### 症状：

> - 客户机无法建立新连接。
> - 客户机无法对失败的连接进行自动重新连接。

> #### 可能原因：

> - 客户机应用程序不是闭合连接，导致连接数超出资源限制。

> 要确认这是否就是问题的起因，请执行下列操作：

> 列出代理的所有连接：

> imqcmd list cxn

> 输出结果将列出所有的连接以及发起每个连接的主机，从而展示特定客户机的特有的打开连接数。

> 要解决此问题，请执行下列操作：

> 重写有问题的客户机，以关闭未使用的连接。

> - 代理未运行或者网络连接有问题。

> 要确认这是否就是问题的起因，请执行下列操作：

> - Telnet 到代理的主端口（例如，默认端口为 7676），并验证代理是否以端口映射器输出结果作为响应。
> - 验证代理进程是否正在主机上运行。

> 要解决此问题，请执行下列操作：

> - 启动代理。
> - 修复网络连接问题。
> - 连接服务处于非活动状态或者已暂停。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查所有连接服务的状态：

> imqcmd list svc

> 如果某个连接服务的状态显示为 unknown 或 paused，则客户机将无法使用该服务建立连接。

> 要解决此问题，请执行下列操作：

> - 如果连接服务的状态显示为 unknown，则它将从活动服务列表中消失 (imq.service.active)。如果是基于 SSL 的服务，那么还可能是因为服务未被正确配置，导致代理在代理日志中生成下面的条目：ERROR [B3009]: Unable to start service ssljms: [B4001]:Unable to open protocol tls for ssljms service...，后面带有关于引起此异常的解释。

> 要正确配置 SSL 服务，请参见“设置通过 TCP/IP 的基于 SSL 的服务”。

> - 如果连接服务的状态显示为 paused，则可以恢复该服务（请参见“暂停和恢复连接服务”）。
> - 连接所要求的线程数不够。

> 要确认这是否就是问题的起因，请执行下列操作：

> 在代理日志中检查下面的条目：WARNING [B3004]: No threads are available to process a new connection on service ...Closing the new connection。

> 另请检查连接服务上的连接数以及当前使用的线程数：

> imqcmd query svc -n serviceName或imqcmd metrics svc -n serviceName -m cxn

> 每个连接都需要两个线程：一个用于外来消息，另一个用于外出消息（请参见“线程池管理器”）。

> 要解决此问题，请执行下列操作：

> - 如果使用专用线程池模型 (imq.service_name. threadpool_model=dedicated)，则最大连接数是该线程池中的最大线程数的一半。因此，要增加连接数，请增加线程池的大小 (imq.service_name.max_threads) 或切换到共享线程池模型。
> - 如果使用共享线程池模型 (imq.service_name. threadpool_model=shared)，则最大连接数是下面两个属性的乘积的一半。连接监视限制 (imq.service_name.connectionMonitor_limit) 和最大线程数 (imq.service_name.max_threads)。因此，要增加连接数，可以增加线程池的大小或增大连接监视限制。
> - 最终，可支持的连接数（或连接上的吞吐量）将达到输出/输出限制。此时，可以使用多代理群集（请参见“使用群集（企业版）”）在群集内的代理实例之间分布连接。
> - Solaris 或 Linux 平台上连接数所需的文件描述符不足（请参见“OS 定义的文件描述符限制”）。

> 要确认这是否就是问题的起因，请执行下列操作：

> 在代理日志中检查类似下面的条目：Too many open files。

> 要解决此问题，请执行下列操作：

> 增大文件描述符限制，如 ulimit 手册页中所述。

> - TCP 待办事项限制了可以同时建立的新连接请求数目。

> TCP 待办事项设置可以存储在系统待办事项 (imq.portmapper.backlog) 中的同时连接请求数限制后，端口映射器才会拒绝额外的请求。（在 Windows 平台上，有一种硬编码的待办事项限制：Windows 台式机限制为 5，而 Windows 服务器限制为 200。）

> 出于待办事项限制而拒绝请求通常是一种由于同时连接请求数过多而导致的瞬态现象。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查代理日志，以查看是否在某些连接请求被接受的同时还有另外一些连接请求被拒绝。被拒绝的连接请求会返回 java.net.ConnectException: Connection refused 消息。

> 要解决此问题，请执行下列操作：

> 下列方法可用于解决 TCP 待办事项限制：

> - 对客户机进行编程，使其在较短的时间间隔后重试所尝试的连接（此方法之所以生效通常是由于此问题的瞬态性）。
> - 增大 imq.portmapper.backlog 的值。
> - 检查客户机是否过于频繁地反复关闭和打开连接。
> - 操作系统限制了并行连接数。

> Windows 操作系统许可证对支持的并行远程连接数进行了限制。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查是否有可用于连接的足够线程（使用 imqcmdquerysvc），并检查您的 Windows 许可协议的条款。如果您可以从本地客户机建立连接，但不能从远程客户机建立连接，则操作系统的限制可能就是问题的起因。

> 要解决此问题，请执行下列操作：

> - 升级 Windows 许可证，以允许更多的连接。
> - 通过设置多代理群集将连接分布在大量代理实例之间。
> - 对用户的验证或授权失败。

> 验证可能因为密码错误而失败，原因是在用户信息库中没有该用户的条目，或者该用户没有对连接服务的访问权限。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查代理日志中的条目，判断是否有 Forbidden 错误消息。此消息指明存在验证错误，但不会指明该错误的原因。

> - 如果使用的是基于文件的用户信息库，请输入下面的命令：

> imqusermgr list -i instanceName -u userName

> 如果输出结果显示的是用户，则说明可能提交了错误的密码。如果输出结果显示错误 [B3048]: User does not exist in the password file，则说明用户信息库中没有该用户的条目。

> - 如果使用的是 LDAP 服务器用户信息库，请使用相应的工具检查是否存在该用户的条目。
> - 检查访问控制属性文件以查看是否对连接服务有访问限制。

> 要解决此问题，请执行下列操作：

> - 如果在用户信息库中没有该用户的条目，那么将该用户添加到用户信息库中（请参见“填充和管理用户信息库”）。
> - 如果使用了错误的密码，请提供正确的密码。
> - 如果访问控制属性设置不当，则编辑访问控制属性文件以授予连接服务权限（请参见“连接访问控制”）。

> ### 问题：连接的吞吐量太慢

> #### 症状：

> - 消息的吞吐量与预期不符。
> - 支持的代理连接数受到限制不是如问题：客户机无法建立连接中所述的原因，而是出于消息的输入/输出速率。

> #### 可能原因：

> - 网络连接或 WAN 太慢。

> 要确认这是否就是问题的起因，请执行下列操作：

> Ping 网络，查看返回 ping 需要多长时间，然后咨询网络管理员。另外还可以使用本地客户机发送并接收消息，并将传送时间与远程客户机（使用网络链路）的传送时间相比。

> 要解决此问题，请执行下列操作：

> 如果连接太慢，则升级网络链路。

> - 与 TCP 相比，连接服务协议本身就慢。例如，基于 SSL 或基于 HTTP 的协议比 TCP 要慢（请参见图 9-5）。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果您使用的是基于 SSL 或基于 HTTP 的协议，请尝试使用 TCP，然后比较传送时间。

> 要解决此问题，请执行下列操作：

> 应用程序的要求通常会限定要使用的协议，因此您可以做的事情就很少了，无非是按“调整传输协议”中所述尝试调整协议而已。

> - 连接服务协议未优化调整。

> 要确认这是否就是问题的起因，请执行下列操作：

> 尝试调整协议，并查看是否发生了变化。

> 要解决此问题，请执行下列操作：

> 尝试按“调整传输协议”中所述调整协议。

> - 消息太大，以致于占用了太多的带宽。

> 要确认这是否就是问题的起因，请执行下列操作：

> 尝试使用较小的消息运行基准检验。

> 要解决此问题，请执行下列操作：

> - 使用 java.util.zip 压缩消息主体。
> - 将消息作为要发送的数据的通知来使用，而使用其他协议移动数据。
> - 使连接吞吐量变慢的可能原因也就是消息传送过程中某个步骤的瓶颈。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果上述的每一条看来都不是造成连接吞吐量变慢的原因，请参见图 9-1以了解其他可能的瓶颈，并检查与下列问题相关的症状：

> - “问题：消息的生成过程发生延迟或变慢”
> - “问题：消息在消息服务器中堆积”
> - “问题：消息服务器吞吐量呈间歇性”

> 要解决此问题，请执行下列操作：

> 遵循前面有关问题疑难解答的各节中提供的问题解决方案指导。

> ### 问题：客户机无法创建消息生成方

> #### 症状：

> - 无法为目标创建消息生成方，客户机收到异常。

> #### 可能原因：

> - 目标被配置为仅允许有限数量的生成方。

> 限制某个目标所能支持的生成方 (maxNumProducers) 数目是避免消息在该目标上堆积的方法之一。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查目标（请参见“显示目标信息”）：

> imqcmd query dst

> 输出结果将显示当前的生成方数目以及 maxNumProducers 的值。如果这两个值相同，则说明生成方的数量已达到所配置的限制。如果新的生成方被代理拒绝，代理将返回 ResourceAllocationException [C4088]: A JMS destination limit was reached 消息，且在代理日志中生成如下条目：[B4183]: Producer can not be added to destination。

> 要解决此问题，请执行下列操作：

> 增大 maxNumProducers 属性的值（请参见“更新目标属性”）。

> - 由于访问控制属性文件中的设置，用户未获得创建消息生成方的授权。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果新的生成方被代理拒绝，代理将返回 JMSSecurityException [C4076]: Client does not have permission to create producer on destination 消息，并在代理日志中生成如下条目：[B2041]:Producer on destination denied 和 [B4051]: Forbidden guest。

> 要解决此问题，请执行下列操作：

> 更改访问控制属性，允许用户生成消息（请参见“目标访问控制”）。

> ### 问题：消息的生成过程发生延迟或变慢

> #### 症状：

> - 发送持久性消息时，send() 方法并没有返回，且客户机发生阻塞。
> - 发送持久性消息时，客户机收到异常。
> - 生成方客户机速度变慢。

> #### 可能原因：

> - 消息服务器上堆满了待办事项（消息堆积在代理的内存中），从而作出使消息生成方减慢的响应。

> 当目标内存中的消息数或消息字节数达到配置的限制时，代理会尝试根据指定的限制行为节约内存资源。下列限制行为会使消息生成方变慢：

> - FLOW_CONTROL：代理不会立即确认收到持久性消息（这样就会阻塞生成方客户机）
> - REJECT_NEWEST：代理拒绝新消息（并为每个被拒绝的持久性消息发出异常）。

> 同样，如果代理范围的内存（对于所有目标）中消息数或消息字节数达到配置的限制，代理将尝试通过拒绝最新的消息来节约内存资源。

> 另外，如果达到了系统内存限制（由于目标或代理范围限制设置不正确），代理将采取越来越严格的操作来防止内存过载，包括限制消息生成方。

> 有关这些机制的讨论，请参见“管理内存资源和消息流”。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果某个消息因为达到了配置的消息限制而被代理拒绝，代理将返回JMSException [C4036]: A server error occurred，并在代理日志中生成下列条目：WARNING [B2011]: Storing of JMS message from IMQconn failed，后面跟有一条表明已达到限制的消息：

> - 如果消息限制位于目标上，则代理将生成类似下面的条目：[B4120]: Can not store message on destination destName because capacity of maxNumMsgs would be exceeded。
> - 如果消息限制是代理范围的，则代理将生成类似下面的条目：[B4024]: The Maximum Number of messages currrently in the system has been exceeded, rejecting message。

> 大多数情况下，您可以通过两种方式在发生拒绝之前检查消息限制情况：分别使用相应的 imqcmd 命令（请分别参见表 9-10和表 9-8）查询目标和代理并检查它们所配置的消息限制设置，以及监视当前在目标上（或者作为一个整体在代理中）的消息数或消息字节数。

> 要解决此问题，请执行下列操作：

> 有很多方法可以解决由于消息变得堆积而导致生成方变慢的问题。

> - 修改目标（或代理范围）上的消息限制，请小心不要超出内存资源。通常，需要根据每个目标来管理内存，这样才不会达到代理范围的消息限制。有关详细信息，请参见“代理调整”。
> - 将目标上的限制行为更改为当达到消息限制时并不减慢消息的生成，而是在内存中废弃消息。例如，您可以指定 REMOVE_OLDEST 和 REMOVE_LOW_PRIORITY 限制行为，这些行为可以删除在内存中堆积的消息（请参见表 6-10）。
> - 代理无法将持久性消息保存到数据存储中。

> 如果代理无法访问数据存储或者将持久性消息写入数据存储，则生成方客户机将阻塞。如果达到了如前所述的目标或代理范围消息限制，也将发生此情况。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果代理无法写入数据存储库，它将在代理日志中生成下列条目之一：[B2011]: Storing of JMS message from connectionID failed 或 [B4004]:Failed to persist message messageID

> 要解决此问题，请执行下列操作：

> - 如果是内置持久性，则尝试增大基于文件的数据存储的磁盘空间。
> - 如果是 JDBC 兼容的数据存储，则检查插入的持久性是否正确配置（请参见附录 B“设置插入的持久性”）。如果是这样，请向数据库管理员咨询，以解决其他数据库问题。
> - 代理的确认超时太短。

> 如果连接太慢或消息服务器反应迟缓（由于 CPU 使用率太高或者内存资源不足导致），代理用于确认收到持久性消息的时间比连接工厂的 imqAckTimeout 属性的值允许的时间要长。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果超出了 imqAckTimeout 值，代理将返回 JMSException [C4000]: Packet acknowledge failed。

> 要解决此问题，请执行下列操作：

> 更改 imqAckTimeout 连接工厂属性的值（请参见“连接工厂受管理对象属性”）。

> - 生成方客户机遇到了 JVM 限制。

> 要确认这是否就是问题的起因，请执行下列操作：

> - 检查客户机应用程序是否收到了内存不足错误。
> - 使用诸如 freeMemory()、MaxMemory() 和 totalMemory() 等运行时方法检查 JVM 堆中的可用内存。

> 要解决此问题，请执行下列操作：

> 调整 JVM（请参见“Java 虚拟机调整”）。

> ### 问题：消息在消息服务器中堆积

> #### 症状：

> - 代理（或特定目标）中的消息数目或消息字节数随着时间稳定增加。

> 要查看消息是否在堆积，请检查代理中的消息数目或消息字节数如何随时间而改变，并比较已配置的限制。首先检查配置的限制：

> imqcmd query bkr

> （注意：imqcmd metrics bkr 子命令不会显示此信息）。

> 然后检查每个目标中的消息堆积情况。

> imqcmd query dst -t destType -n destName
> 或
> imqcmd metrics dst -t destType -n destName -m ttl

> 要检查消息是否已超出配置的目标或代理范围限制，请在代理日志中检查如下条目：WARNING [B2011]: Storing of JMS message from failed。此条目后面接有另一个阐明限制已超出的条目。

> - 消息的生成发生了延迟，或者生成的消息被代理拒绝。
> - 消息到达使用方的时间过长。

> #### 可能原因：

> - 客户机代码缺陷：使用方不确认消息。

> 消息会保留在目标中，直到消息所发送到的所有使用方都进行了确认为止。因此，如果客户机没有确认已使用的消息，该消息会在目标中堆积，而不会删除。

> 例如，客户机代码可能会存在下列缺陷：

> - 使用 CLIENT_ACKNOWLEDGEMENT 或事务会话的使用方可能没有定期调用 Session.acknowledge() 或 Session.commit()。
> - 使用 AUTO_ACKNOWLEDGE 会话的使用方可能因为某种原因而挂起。

> 要确认这是否就是问题的起因，请执行下列操作：

> 如果消息服务器不繁忙，即消息流入和流出目标的速率很低，则说明消息可能由于未被确认而堆积。

> 检查消息流入和流出代理的速率。

> imqcmd metrics bkr -m rts

> 然后检查每个单独目标的流速：

> imqcmd metrics bkr -t destType -n destName -m rts

> 再检查客户机代码以查看消息是否被正确确认。

> - 主题目标上有非活动的长期订阅。

> 如果长期订阅是非活动的，则消息会存储在目标中，直到相应的使用方变为活动状态且能够使用这些消息为止。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查每个主题目标上的长期订阅的状态：

> imqcmd list dur -d destName

> 要解决此问题，请执行下列操作：

> 可以采用下列任意操作：

> - 清除所有存在问题的长期订阅的消息（请参见“管理长期订阅”）。
> - 指定主题的消息限制以及限制行为属性（请参见表 6-10）。例如，您可以指定 REMOVE_OLDEST 和 REMOVE_LOW_PRIORITY 限制行为，这些行为可以删除在内存中堆积的消息。
> - 清除来自相应目标的所有消息（请参见“清除目标”）。
> - 限制可以在内存中保留消息的时间：您可以重写生成方客户机以便对每个消息都设置一个有效期值。您可以通过设置 imqOverrideJMSExpiration 和 imqJMSExpiration 连接工厂属性（请参见表 7-3）来覆盖共享一个连接的所有生成方的这些设置。
> - 队列中可以使用消息的使用方太少。

> 如果消息可以传送到的活动使用方太少，队列目标可能会随着消息的堆积而变得堆满了待办事项。只要有下列任何原因，都会发生此情况：

> - 目标的活动使用方太少。
> - 使用方客户机建立连接失败。
> - 活动使用方没有使用与队列中的消息匹配的选择器。

> 要确认这是否就是问题的起因，请执行下列操作：

> 要确定使用方不可用的原因，请检查目标上活动使用方的数量：

> imqcmd metrics dst -n destName -t q -m con

> 要解决此问题，请执行下列操作：

> 您可以根据使用方不可用的原因采取下列任意操作：

> - 通过启动其他使用方客户机来为队列创建更多的活动使用方。
> - 调整 imq.consumerFlowLimit 代理属性以优化对多个使用方的队列传送（请参见“多使用方队列性能”）。
> - 指定队列的消息限制以及限制行为属性（请参见表 6-10）。例如，您可以指定 REMOVE_OLDEST 和 REMOVE_LOW_PRIORITY 限制行为，这些行为可以删除在内存中堆积的消息。
> - 清除来自相应目标的所有消息（请参见“清除目标”）。
> - 限制消息可以在内存中保留的时间：您可以重写生成方客户机以对每个消息都设置一个有效期值，也可以通过设置 imqOverrideJMSExpiration 和 imqJMSExpiration 连接工厂属性（请参见表 7-3）来覆盖共享一个连接的所有生成方的这些设置。
> - 消息使用方的处理速度太慢，跟不上消息生成方的速度。

> 在这种情况下，主题的订阅者或队列的接收者使用消息的速度要比生成方发送消息的速度慢。会有一个或多个目标因为这种不平衡而堆满了消息。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查消息流入和流出代理的速率：

> imqcmd metrics bkr -m rts

> 然后检查每个单独目标的流速：

> imqcmd metrics bkr -t destType -n destName -m rts

> 要解决此问题，请执行下列操作：

> - 优化使用方客户机代码。
> - 对于队列目标，增大活动使用方的数目（请参见“多使用方队列性能”）。
> - 客户机的确认处理过程减慢了消息的使用。

> 影响对客户机确认过程的处理有两个因素：

> - 在处理客户机确认的过程中会消耗大量的代理资源。作为结果，如果使用方客户机会一直阻塞到代理对客户机确认进行确认时为止，则对于这样的确认模式，消息的使用会变慢。
> - JMS 有效负荷消息和 Message Queue 控制消息（例如客户机确认）共享同一连接。结果，控制消息可能会被 JMS 有效负荷消息阻挡，从而使消息的使用变慢。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查与数据包流相关的消息流。如果每秒数据包数与消息数的不成比例，则客户机确认可能有问题。

> 另外请检查客户机是否收到 JMSException [C4000]: Packet acknowledge failed 消息。

> 要解决此问题，请执行下列操作：

> - 修改客户机使用的确认模式，例如切换到 DUPS_OK_ACKNOWLEDGEMENT 或 CLIENT_ACKNOWLEDGEMENT。
> - 如果使用 CLIENT_ACKNOWLEDGEMENT 或事务会话，则将更多数量的消息组合到一个确认中。
> - 调整使用方和连接流控制参数（请参见“客户机运行时消息流调整”）。
> - 代理无法适应生成的消息。

> 在这种情况下，消息流入代理的速度比代理可以将它们路由并发送到使用方的速度要快。代理的迟缓可能由下列任一或全部内容的限制所导致：CPU、网络套接字读/写操作、磁盘读/写操作、内存分页、持久性存储库或 JVM 内存限制。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查有无其他原因导致此问题。

> 要解决此问题，请执行下列操作：

> - 升级计算机或数据存储的速度。
> - 使用代理群集将负荷分布到多个代理实例之间。

> ### 问题：消息服务器吞吐量呈间歇性

> #### 症状：

> - 消息的吞吐量不定期地下降，然后又恢复正常性能。

> #### 可能原因：

> - 代理的内存资源非常低。

> 由于目标和代理的限制设置得不正确，代理采取了越来越严格的措施以防止内存过载，这样就导致代理变得非常迟缓，直到消息的堆积得到清除为止。

> 要确认这是否就是问题的起因，请执行下列操作：

> 在代理日志中检查内存小的情况 ([B1089]: In low memory condition, broker is attempting to free up resources)，该情况后面会接有一个描述新内存状态和已用内存总量的条目。

> 另外请检查 JVM 堆中的可用内存：

> imqcmd metrics bkr -m cxn

> 当总 JVM 内存接近 JVM 内存最大值时，可用内存就会很小。

> 要解决此问题，请执行下列操作：

> - 调整 JVM（请参见“Java 虚拟机调整”）。
> - 增大系统交换空间。
> - 正在发生 JVM 内存回收（垃圾收集）。

> 内存回收会定期清扫整个系统，以释放内存。发生此操作时，所有的线程都会阻塞。要释放的内存量以及 JVM 堆的大小越大，因内存回收而导致的延迟就越长。

> 要确认这是否就是问题的起因，请执行下列操作：

> 监视计算机上的 CPU 使用。发生内存回收时，它会产生显著下降。

> 另外，使用下列命令行选项启动代理：

> -vmargs -verbose:gc

> 其标准输出指明发生内存回收的时间。

> 要解决此问题，请执行下列操作：

> 在多个 CPU 的计算机中，将内存回收设置为并行发生：

> -XX:+UseParallelGC=true

> - JVM 正在使用实时编译器以提高性能。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查有无其他原因导致此问题。

> 要解决此问题，请执行下列操作：

> 让系统运行一段时间，性能应该会有所改善。

> ### 问题：消息无法到达使用方

> #### 症状：

> - 使用方未收到生成方发送的消息。

> #### 可能原因：

> - 限制行为导致在代理上删除了消息。

> 如果目标内存中的消息数目或消息字节数达到了配置限制，代理将尝试节约内存资源。当达到限制时，代理将采取下列三个可配置的行为，从而导致消息丢失：

> - REMOVE_OLDEST：删除最旧的消息
> - REMOVE_LOW_PRIORITY：删除根据消息时间排列时优先级最低的消息
> - REJECT_NEWEST:拒绝新消息（发出一个有关被拒绝的持久性消息的异常）。

> 如果代理内存中的消息数量或消息字节数达到配置的限制，代理将尝试通过拒绝最新的消息来节约内存资源。

> 要确认这是否就是问题的起因，请执行下列操作：

> 在代理日志中检查下面的条目：WARNING [B2011]: Storing of JMS message from failed。此条目后面接有另一个阐明限制已超出的条目。但是不会有显示对消息的删除操作的条目。

> 要解决此问题，请执行下列操作：

> 更改限制或更改行为。

> - 消息超时值过期

> 代理将删除超时值已过期的消息。如果目标上完全堆满了消息，有效期值过短的消息将被删除。

> 要确认这是否就是问题的起因，请执行下列操作：

> 在代理日志文件中检查如下条目： Expiring Messages: Expired n messages。

> 要解决此问题，请执行下列操作：

> 使用覆盖

> - 不同计算机的系统时钟不同步。

> 如果时钟之间不同步，则代理对消息有效期的计算可能会错误，从而导致消息超过它们的截止时间而被删除。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查所有计算机上的时钟。

> 要解决此问题，请执行下列操作：

> 同步时钟（请参见“系统时钟设置”）。

> - 使用方客户机未能启动在某个连接上的消息传送。

> 除非客户机代码建立了连接，并在该连接上启动了消息传送，否则消息将无法传送。

> 要确认这是否就是问题的起因，请执行下列操作：

> 检查客户机代码是否能建立连接并启动消息传送。

> 要解决此问题，请执行下列操作：

> 重写客户机代码，以建立连接并启动消息传送。

> ##

> 调整配置以提高性能

> ### 系统调整

> 以下各节讲述您可以对操作系统、JVM 和通信协议所作的调整。

> #### Solaris 调整：CPU 使用、分页/交换/磁盘 I/O

> 有关对操作系统的调整，请参见系统文档。

> #### Java 虚拟机调整

> 默认情况下，代理使用大小为 192MB 的 JVM 堆。通常，这对于较大的消息负荷来说太小，应该增大。

> 当代理快要耗尽 Java 对象使用的 JVM 堆空间时，它将使用各种技术（如流控制和消息交换）来释放内存。在极端情况下，代理甚至关闭客户机连接以释放内存并减少消息内流。所以最好将最大 JVM 堆空间设置得足够大，以避免这种情况。

> 但是，与系统的物理内存相比，如果最大 Java 堆空间设置过大，代理将继续增大 Java 堆空间，直至整个系统耗尽内存。这会导致性能的降低、不可预计的代理崩溃和/或影响系统中运行的其他应用程序和服务的行为。通常，需要有足够的物理内存以便操作系统和其他应用程序在计算机上运行。

> 总的说来，好的方法是：估算正常和峰值系统内存容量，并配置 Java 堆大小，使其足以提供良好性能，但同时不应过大，以免引起系统内存问题。

> 要更改代理的最小和最大堆大小，请在启动代理时使用 -vmargs 命令行选项。例如：

> /usr/bin/imqbrokerd -vmargs "-Xms256m -Xmx1024m"

> 此命令会将启动 Java 堆大小设置为 256MB，将最大 Java 堆大小设置为 1GB。

> - 在 Solaris 上，如果通过 /etc/rc（即 /etc/init.d/imq）启动代理，请在 /etc/imq/imqbrokerd.conf 文件中指定代理的命令行参数。有关详细信息，请参见该文件中的注释。
> - 在 Windows 上，如果将代理作为 Window 服务启动，请使用 imqsvcadmin install 命令的 -vmargs 选项指定 JVM 参数。请参见“服务管理器实用程序 (imqsvcadmin)”。

> 在任何情况下，请通过检查代理的日志文件或通过使用 imqcmd metrics bkr -m cxn 命令验证设置。

> #### 调整传输协议

> 选择了符合应用程序需要的协议后，基于该协议进行其他调整可以提高性能。

> 协议的性能可以使用下面三个代理属性进行修改：

> - imq.protocol protocol_type nodelay
> - imq.protocol protocol_type inbufsz
> - imq.protocol protocol_type outbufsz

> 对于 TCP 和 SSL 协议，这些属性会影响客户机和代理之间的消息传送速度。对于 HTTP 和 HTTPS 协议，这些属性会影响 Message Queue 隧道 servlet（在 Web 服务器上运行）和代理之间的消息传送速度。对于 HTTP/HTTPS 协议，还有其他可以影响性能的属性（请参见“HTTP/HTTPS 调整”）。

> 协议调整属性将在以下各节中讲述。

> ##### nodelay

> nodelay 属性影响给定协议的 Nagle 算法（TCP/IP 上的 TCP_NODELAY 套接字级选项的值）。Nagle 算法用于提高使用慢速连接（例如广域网 (WAN)）的系统上的 TCP 性能。

> 如果使用了此算法，TCP 将通过把多个数据捆绑为较大的数据包来尝试防止将多个小块数据发送到远程系统。如果写入套接字中的数据没有填满需要的缓冲区大小，协议将延迟发送数据包，直到缓冲区被填满，或者已经过了特定的延迟时间为止。填满了缓冲区或者发生了超时后，数据包将发送。

> 对于大多数消息传送应用程序，如果数据包发送过程中没有延迟（Nagle 算法未启用），则性能是最佳的。这是因为客户机和代理之间的大多数交互都是请求/响应交互：客户机向代理发送数据包，并等待响应。例如，典型的交互包括：

> - 创建连接
> - 创建生成方或使用方
> - 发送持久性消息（代理确认收到消息）
> - 在 AUTO_ACKNOWLEDGE 或 CLIENT_ACKNOWLEDGE 会话中发送客户机确认（代理确认对客户机确认的处理）

> 对于这些交互，大多数数据包都比缓冲区大小要小。这意味着如果使用 Nagle 算法，代理会在向使用方发送响应之前延迟几毫秒。

> 但是，在连接较慢以及不需要代理响应的情况下，Nagle 算法可以提高性能。例如，当客户机发送非持久性消息或者当客户机确认未被代理确认（DUPS_OK_ACKNOWLEDGE 会话）时，就属于这样的情况。

> ##### inbufsz/outbufsz

> inbufsz 属性用于在读取来自套接字的数据的输入流上设置缓冲区大小。同样，outbufsz 用于设置代理用来将数据写入套接字的输出流的缓冲区大小。

> 通常，这两个参数都应该设置为比收发的平均数据包要稍大的值。一个很好的经验是将这些属性值设为平均数据包的大小再加上 1k（舍入为最接近的 k 值）。

> 例如，如果代理正在接收主体大小为 1k 的数据包，则该数据包的总体大小（消息主体 + 标题 + 属性）约为 1200 字节。大小为 2k（2048 字节）的 inbufsz 可以提供合理的性能。

> 增大 inbufsz 或 outbufsz（使其大于该值）可以稍微提高性能，但这样会增加每个连接所需的内存。

> 图 9-6 显示对大小为 1K 的数据包更改 inbufsz 的结果。

> 图 9-7 更改大小为 1K（1024 字节）的数据包的 inbufsz 的结果

> 图 9-8 显示对大小为 1K 的数据包更改 outbufsz 的结果。

> 图 9-8 更改大小为 1K（1024 字节）的数据包的 outbufsz 的结果

> ##### HTTP/HTTPS 调整

> 除了前面两节讨论的一般属性之外，HTTP/HTTPS 的性能还受到客户机向作为 Message Queue 隧道 servlet 宿主的 Web 服务器发出 HTTP 请求的速度的限制。

> Web 服务器可能需要优化，以处理单个套接字上的多个请求。在 JDK 1.4 版及更高版本中，对 Web 服务器的 HTTP 连接会一直保持（对 Web 服务器的套接字保持打开），以使 Web 服务器在处理多个 HTTP 请求时使用的资源最小化。如果使用 JDK 1.4 版的客户机应用程序的性能比运行早期 JDK 版本的同一应用程序要低，则可能需要调整 Web 服务器的保持配置参数以提高性能。

> 除了这样的 Web 服务器调整之外，您还可以调整客户机轮询 Web 服务器的频率。HTTP 是一种基于请求的协议。这意味着使用基于 HTTP 的协议的客户机需要定期地检查 Web 服务器，以查看是否有消息在等待。imq.httpjms.http.pullPeriod 代理属性（以及相应的 imq.httpsjms.https.pullPeriod 属性）可指定 Message Queue 客户机运行时轮询 Web 服务器的频率。

> 如果 pullPeriod 值为 -1（默认值），客户机运行时将在前一个请求返回后立即轮询服务器，从而将各个客户机的性能最大化。结果，每个客户机连接都会在 Web 服务器中独占一个请求线程，这样可能会耗费 Web 服务器资源。

> 如果 pullPeriod 值为正数，客户机运行时将定期向 Web 服务器发送请求，以查看是否有挂起的数据。在这种情况下，客户机不会独占 Web 服务器中的请求线程。因此，如果有大量的客户机在使用 Web 服务器，您可以通过将 pullPeriod 设为正值来节约 Web 服务器资源。

> #### 调整基于文件的持久性存储库

> 有关调整基于文件的持久性存储库的信息，请参见“内置的持久性”。

> ### 代理调整

> 以下各节讲述为了提高性能而可以对代理属性作出的调整。

> #### 内存管理：增大代理在负荷下的稳定性

> 内存管理可以在逐个目标的级别上配置，也可以在系统范围级别（集中地对于所有目标）上配置。

> ##### 使用目标限制

> 有关目标限制的信息，请参见“管理目标”。

> ##### 使用系统范围限制

> 如果消息生成方的数目超过消息使用方的数目，则消息可能在代理中堆积。尽管代理确实包含限制生成方和在内存过小的情况下将消息交换出活动内存的机制（请参见“管理内存资源和消息流”），最好还是对代理可以保持的消息数和消息字节总数进行严格限制。

> 可以通过设置 imq.system.max_count 和 imq.system.max_size 代理属性来控制这些限制。有关设置代理属性的信息，请参见“编辑实例配置文件”或imqbrokerd 选项概述。

> 例如

> imq.system.max_count=5000

> 上面定义的值表示代理最多仅能保留 5000 条未传送/未确认的消息。如果发送了其他消息，它们将被代理拒绝。如果消息是持久性的，当生成方尝试发送该消息时，会收到一个异常。如果消息是非持久性的，代理将自行废弃该消息。

> 若要让非持久性消息像持久性消息那样返回异常，请对客户机使用的连接工厂对象设置下列属性：

> imqAckOnProduce = true

> 上面的设置会降低向代理发送非持久性消息的性能（客户机会等待回复后才发送下一条消息），但通常这是可以接受的，因为内流到代理的消息通常不是系统瓶颈。

> 如果在发送消息的过程中返回了异常，客户机应该暂停一会，然后再次重试发送。

> #### 多使用方队列性能

> 多队列使用方处理队列目标中消息的效率取决于可配置的队列目标属性，即活动使用方数目 (maxNumActiveConsumers) 和一次性可以传送到使用方的最大消息数 (consumerFlowLimit)。表 6-10 中介绍了这些属性。

> 要达到优化的消息吞吐量，必须有足够数量的活动使用方以适应队列的消息生成方的速率，并且队列中的消息必须以最大化使用速率的方式路由和传送给活动使用方。“多个使用方的队列传送”中介绍了在多个使用方之间平衡消息传送的一般机制。

> 如果消息在队列中堆积，这可能是因为没有足够的活动使用方来处理消息负荷。也可能是每批传送给使用方的消息太多，导致消息在使用方堆积。例如，如果每批的大小 (consumerFlowLimit) 太大，某个使用方就可能会收到一个队列中的所有消息，而其他活动使用方则一个也没收到。如果使用方速度特别快，这也不会成为问题。

> 但是如果使用方相对较慢，而您又希望将消息均匀地分布给它们，则需要将每批的大小减小。每批的大小越小，将消息传送到使用方所需的开销就越多。但是对于较慢的使用方，使用较小的批大小通常却能获得网络性能的提升。

> ### 客户机运行时消息流调整

> 本节讨论影响性能的流控制行为（请参见“客户机运行时配置”）。这些行为可配置为连接工厂被管理对象的属性。有关设置连接工厂属性的信息，请参见第 7 章“管理受管理对象”

> #### 消息流测量

> 客户机收发的消息（JMS 消息）以及 Message Queue 控制消息通过同一客户机 代理连接传递。如果控制消息（例如代理确认）的传送被 JMS 消息阻挡，则会发生延迟。为防止此类拥塞，Message Queue 会测量通过连接的 JMS 消息流。

> JMS 消息是分批的（由 imqConnectionFlowCount 属性指定），因此只会传送集合编号；传送完一批后，JMS 消息的传送会挂起，而挂起的控制消息会传送。当另一批 JMS 消息传送后，接着又传送排队等候的控制消息，这样循环往复。

> 如果客户机正在执行需要代理作出大量响应的操作，imqConnectionFlowCount 的值应该保持较低；例如，当客户机正在使用 CLIENT_ACKNOWLEDGE 或 AUTO_ACKNOWLEDGE 模式、持久性消息、事务、队列浏览器时，或者当客户机正在添加或删除使用方时。从另一方面说，如果客户仅在使用 DUPS_OK_ACKNOWLEDGE 模式的连接上有简单的使用方，则可以增大 imqConnectionFlowCount 而不会降低性能。

> #### 消息流限制

> 在遇到本地资源（例如内存）限制之前，存在 Message Queue 客户机运行时可以处理的 JMS 消息数限制。如果达到了此限制，性能将受影响。因此，Message Queue 可以让您限制每个使用方（或每个连接）能够通过连接传送和能够在客户机运行时中缓冲以等待使用的消息数。

> ##### 基于使用方的限制

> 当传送到客户机运行时的 JMS 消息数超过任意使用方的 imqConsumerFlowLimit 值时，将停止传送该使用方的消息。仅当该使用方的未使用消息数下降到低于 imqConsumerFlowThreshold 设置的值时才会恢复。

> 下例说明了如何使用这些限制：以主题使用方的默认设置为例

> imqConsumerFlowLimit=1000

> imqConsumerFlowThreshold=50

> 创建使用方后，代理将向此使用方传送第一批 1000 条消息（前提是有这么多），中间不会暂停。发送 1000 条消息后，代理将停止传送，除非客户机运行时要求更多消息。客户机运行将保留这些消息，直到应用程序处理它们为止。在要求代理发送下一批消息之前，客户机运行时会允许应用程序使用至少 50% (imqConsumerFlowThreshold) 的消息缓冲区容量（即 500 条消息）。

> 在同等情况下，如果阈值为 10%，则客户机运行时会等待应用程序使用至少 900 条消息，然后才会要求发送下一批消息。

> 下一批消息的大小按如下计算：

> imqConsumerFlowLimit - (current number of pending msgs in buffer)

> 因此，如果 imqConsumerFlowThreshold 为 50%，则下一批的大小会在 500 和 1000 之间波动，这取决于应用程序处理消息的速度。

> 如果 imqConsumerFlowThreshold 设置得过高（接近 100%），代理就会发送较小的分批消息，这样会降低消息的吞吐量。如果该值过低（接近 0%），则客户机可以在代理传送下一组消息之前处理完剩余的缓冲消息，从而导致消息吞吐量的降低。通常，除非您有特别的性能或可靠性考虑，否则不需要更改 imqConsumerFlowThreshold 属性的默认值。

> 基于使用方的流控制（特别是 imqConsumerFlowLimit）是管理客户机运行时中内存的最好方法。通常，根据客户机应用程序的不同，您应该知道在任意连接上需要支持的使用方数、消息的大小以及可用于客户机运行时的内存总量。

> ##### 基于连接的限制

> 但是在某些客户机应用程序中，使用方数量不是确定的，这取决于最终用户所作的选择。在这些情况下，您仍可以使用连接级流限制来管理内存。

> 连接级流控制可以限制针对一个连接上的所有使用方而缓冲的总消息数。如果此数字超过了 imqConnectionFlowLimit，则通过该连接进行的消息传送将停止，直到该总数降到连接限制以下为止（只有在将 imqConnectionFlowLimitEnabled 属性设置为 true 时，imqConnectionFlowLimit 才会启用）。

> 在会话中排队等候的消息数是使用该会话的消息使用方数量以及每个使用方的消息负荷的函数。如果客户机在生成或使用消息时表现出延迟，您通常可以通过下列操作提高性能：重新设计应用程序，以便在更大数量的会话之间分布消息生成方和使用方，或者在更大数量的连接之间分布会话。

> 上一章 目录 索引 下一章

> 版权所有 2004 Sun Microsystems, Inc. 保留所有权利。