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

> ## 第 2 章
> Message Queue 消息传送系统

> 本章介绍 Sun Java System Message Queue 消息传送系统，其中重点说明的是系统的主要组成部分（如图 2-1 所示），并阐述了这些组成部分如何配合工作来提供可靠的消息传送。

> 图 2-1 Message Queue 系统的体系结构

> Message Queue 消息传送系统的主要组成部分（如图 2-1 所示）包括：

> - Message Queue 消息服务器
> - Message Queue 客户机运行时
> - Message Queue 受管理对象
> - Message Queue 管理

> 前三个组成部分将在下面的小节中进行详细说明。最后一个部分将在第 3章“Message Queue 管理任务和工具”中介绍。

> ##

> Message Queue 消息服务器

> 本节介绍 Message Queue 消息服务器（如图 2-1 所示）的各个组成部分，包括：

> 代理 Message Queue 代理为 Message Queue 消息传送系统提供传送服务。消息传送依赖于大量支持组件，这些组件负责处理连接服务、消息的路由和传送、持久性、安全性以及日志记录（有关详细信息，请参见“代理”）。消息服务器可以使用一个或多个代理实例（请参见“多代理群集（企业版）”）。

> 物理目标 消息的传送过程分为两个阶段：首先从生成消息的客户机（生成方客户机）将消息发送到由代理维护的物理目标，然后再从目标发送到一个或多个使用消息的客户机（使用方客户机）。物理目标是指代理的物理内存和/或持久性存储器中的位置（有关详细信息，请参见“物理目标”）。

> ### 代理

> 在 Message Queue 消息传送系统中，消息传送（从生成方客户机到目标，然后再从目标到一个或多个使用方客户机）由代理（或以串连模式工作的代理实例群集）来执行。要执行消息传送，代理必须建立与客户机之间的通信通道、执行验证和授权、适当的路由消息、确保可靠传送并提供用于监视系统性能的数据。

> 为了实现这么多复杂的功能，代理使用了大量的各种内部组件，每个组件都在传送过程中担当着各自不同的角色。图 2-2 所示为代理组件，表 2-1 则对这些组件进行了简要说明。消息路由器组件执行关键的消息路由和传送服务，而其他组件则提供消息路由器所依赖的重要的支持服务。

> 图 2-2 代理服务组件

> 表 2-1 主要代理服务组件及功能

> 组件 | 说明/功能
> --- | ---
> 消息路由器 | 管理消息的路由和传送，这里的消息包括：JMS 消息以及在 Message Queue 消息传送系统中用于支持 JMS 消息传送的控制消息。
> 连接服务 | 管理代理和客户机之间的物理连接，用于传输外来和外出消息。
> 持久性管理器 | 管理向持久性存储器写入数据，这样即使系统发生故障也不会导致无法传送 JMS 消息。
> 安全性管理器 | 为请求连接到代理的用户提供验证服务，并为通过验证的用户提供授权服务（访问控制）。
> 监视服务 | 生成度量依据和诊断信息，这些内容可以写入到大量的输出通道中。管理员利用这些内容进行监视和管理。

> 可以根据负荷条件、应用程序的复杂性等因素配置这些内部组件，以优化代理的性能。下面的几个小节将详细介绍不同组件执行的功能及其属性（可以配置这些属性来影响代理的行为）。

> #### 连接服务

> Message Queue 代理既支持与 Message Queue 应用程序客户机的通信，也支持与 Message Queue 管理客户机的通信（请参见“Message Queue 管理工具”）。各个服务取决于其服务类型和协议类型。

> 服务类型 指定服务提供的是 JMS 消息传送 (NORMAL) 服务，还是 Message Queue 管理 (ADMIN) 服务。

> 协议类型 指定支持服务的基本传输协议层。

> 表 2-2 显示了 Message Queue 代理当前支持的连接服务：

> 表 2-2 代理支持的连接服务

> 服务名称 | 服务类型 | 协议类型
> --- | --- | ---
> jms | NORMAL | tcp
> ssljms（企业版） | NORMAL | tls（其安全性基于 SSL）
> httpjms（企业版） | NORMAL | http
> httpsjms（企业版） | NORMAL | https（其安全性基于 SSL）
> admin | ADMIN | tcp
> ssladmin（企业版） | ADMIN | tls（其安全性基于 SSL）

> 可以将代理配置为运行以上任一或全部连接服务。每个连接服务仅在由代理的主机名和端口号指定的特定端口上可用。端口可动态分配，或者可指定连接服务可用的端口。

> 每项服务都具有一个线程池管理器，并向通用端口映射器服务注册它本身，如图 2-3 所示。

> 图 2-3 连接服务支持

> ##### 端口映射器

> Message Queue 提供了一个端口映射器，用于将端口映射到不同的连接服务。端口映射器本身位于标准端口号 7676。当客户机建立与代理的连接时，首先与端口映射器进行通信，请求其所需的连接服务端口号。

> 在配置 jms、ssljms、admin 和 ssladmin 等连接服务时，也可以为它们分配静态端口号，但这是在特殊情况下使用的手段（例如，通过防火墙连接），一般不建议使用。分别使用表 C-1 和表 C-3（这两个表格位于附录 C“HTTP/HTTPS 支持（企业版）”）中说明的属性来配置 httpjms 和 httpsjms 服务。

> ##### 线程池管理器

> 每个连接服务都是多线程的，从而支持多个连接。这些连接所需的线程在线程池中进行维护，而线程池又由线程池管理器组件来管理。通过配置线程池管理器，可以设置线程池中维护的线程的最大和最小数量。当连接需要线程时，这些线程将被添加到线程池中。当线程数量超过最小数量时，系统将关闭变为空闲状态的线程，直到达到最小阈值，以此来节省内存资源。您希望此值足够大，这样就不必不断创建新线程。如果连接负荷较重，线程数量可能会增加，直到达到线程池的最大数量。此后，连接不得不一直等待，直到某个线程可用。

> 线程池中的线程可专用于单个连接（专用模型），也可根据需要分配到多个连接（共享模型）。

> 专用模型 每个到代理的连接需要两个专用线程：一个用于处理连接的外来消息，另一个用于处理连接的外出消息。这样，连接的数量就被限制为线程池中最大线程数量的一半，但却提供了较高的性能。

> 共享模型（企业版） 只要发送或接收消息，连接就会由共享线程处理。由于每个连接不需要专用线程，此模型增加了连接服务可支持的连接数量，因而，也增加了代理可支持的连接数量。但这同时带来了共享线程相关的某些性能开销。线程池管理器使用一组分配器线程来监视连接活动并根据需要将连接分配到线程。可通过限制每个此类分配器线程所监视的连接的数量使此活动带来的性能开销最小化。

> ##### 安全性

> 每个连接服务均支持特定的验证和授权（访问控制）功能（请参见“安全性管理器”）。

> ##### 连接服务属性

> 表 2-3 所示为与连接服务相关的可配置属性。（有关配置这些属性的说明，请参见第 5 章“启动与配置代理”。）

> 表 2-3 连接服务属性

> 属性名称 | 说明
> --- | ---
> imq.service.activelist | 按名称列出启动代理时将变为活动状态的连接服务，服务之间用逗号分隔。支持的服务包括：jms、ssljms、httpjms、httpsjms、admin 和 ssladmin。 默认值：jms 和 admin
> imq.ping.interval | 代理通过连接连续尝试 ping Message Queue 客户机运行时的时间周期。默认值：120 秒
> imq.hostname | 指定当有多个主机可用（例如，一台计算机中安装了多个网络接口卡）时所有连接服务将绑定到的主机（主机名或 IP 地址）。默认值：所有可用的 IP 地址
> imq.portmapper.port | 指定代理的主端口，即端口映射器所在的端口。如果主机上运行多个代理实例，则必须为每个实例分配唯一的端口映射器端口。 默认值： 7676
> imq.portmapper.hostname | 指定当有多个主机可用（例如，一台计算机中安装了多个网络接口卡）时端口映射器将绑定到的主机（主机名或 IP 地址）。 默认值：继承 imq.hostname 的值
> imq.portmapper.backlog | 指定端口映射器在拒绝请求之前可处理的并发请求的最大数量。该属性设置了可存储在操作系统待办事项中等待端口映射器处理的请求的数量。默认值： 50
> imq.service_name. protocol_type1.port | 仅适用于 jms、ssljms、admin 和 ssladmin 服务，指定命名的连接服务的端口号。 默认值：0（端口由端口映射器动态分配） 要配置 httpjms 和 httpsjms 连接服务，请参见附录 C“HTTP/HTTPS 支持（企业版）”。
> imq.service_name. protocol_type1.hostname | 仅适用于 jms、ssljms、admin 和 ssladmin 服务，指定当有多个主机可用（例如，一台计算机中安装了多个网络接口卡）时命名的连接服务将绑定到的主机（主机名或 IP 地址）。 默认值：继承 imq.hostname 的值
> imq.service_name. min_threads | 指定线程数量，达到该数量后，线程池中将维护此数量的线程供命名的连接服务使用。 默认值：取决于连接服务（请参见表 5-1）。
> imq.service_name. max_threads | 指定线程数量，达到该数量后，新的线程将不会被添加到线程池中供命名的连接服务使用。该数量必须大于零，并且必须大于 min_threads 的值。 默认值：取决于连接服务（请参见表 5-1）。
> imq.service_name. threadpool_model | 为命名的连接服务指定线程是专用于特定的连接 (dedicated)，还是根据需要由多个连接共享 (shared)。共享模型（线程池管理）将增加代理支持的连接数量，但只能用于 jms 和 admin 连接服务。 默认值：取决于连接服务（请参见表 5-1）。
> imq.shared. connectionMonitor_limit | 仅适用于共享线程池模型，用于指定分配器线程可监视的连接的最大数量。（系统会分配足够多的分配器线程来监视所有连接。）此值越小，系统向线程分配活动连接的速度就越快。值 -1 表示没有限制。 默认值：取决于操作系统（请参见表 5-1）。

> 1 protocol_type 为表 2-2 中指定的协议类型。

> #### 消息路由器

> 使用支持的连接服务在客户机与代理之间建立起连接后，即可进行消息的路由和传送。

> ##### 基本传送机制

> 广义来讲，代理处理的消息可分为两类：由生成方客户机发往使用方客户机的 JMS 消息（即有效负荷消息）以及从客户机发出或发往客户机的大量用于支持 JMS 消息传送的控制消息。

> 如果外来消息为 JMS 消息，代理会根据其目标的类型（队列或主题）将其发送到使用方客户机：

> - 如果目标为主题，JMS 消息将立即被路由到此主题的所有活动订阅者。对于未处于活动状态的长期订阅者，消息路由器将保留消息，直到订阅者变为活动状态后再将消息传送给该订阅者。
> - 如果目标为队列，JMS 消息将被放置在相应的队列中，并在到达队列前端时被传送到相应的使用方。消息到达队列前端的顺序取决于它们进入队列的顺序以及它们的优先级。

> 消息路由器将消息传送到其所有目标使用方后，将从内存中删除此消息。如果该消息为持久性消息（请参见“可靠消息传送”），还会将其从代理的持久性数据存储中删除。

> ##### 可靠传送：确认和事务

> 如果增加可靠传送（请参见“可靠消息传送”）的要求，则刚才讨论的传送机制就会复杂得多。可靠传送涉及两个方面：一是确保消息成功传送到代理以及从代理成功传送出去，二是确保在实际传送消息前，代理没有丢失消息或传送信息。。

> 为了确保至代理和出自代理的消息传送能够成功，Message Queue 使用了大量称为确认的控制消息。

> 例如，当生成方向目标发送 JMS 消息（有效负荷消息而非控制消息）时，代理会发回一条说明它已接收到 JMS 消息的控制消息，这条控制消息就是代理确认。（默认情况下，只有当生成方将 JMS 消息指定为持久性消息时，Message Queue 才会进行上述操作。）生成方客户机使用代理确认来确保至目标的传送成功（请参见“消息生成”）。

> 同样，当代理将 JMS 消息传送到使用方时，使用方客户机会发回一个确认，说明它已接收并处理了此消息。客户机可以在创建会话对象时指定发送这些确认的自动程度和频率，但原则是消息路由器在收到每个消息使用方（即接收它所传送的消息的客户机，例如某个主题的每个订阅者）的确认之前，不会从内存中删除 JMS 消息。

> 对于某个主题的长期订阅者，消息路由器会将每条 JMS 消息保留在该目标中，以便在每个长期订阅者变为活动使用方时将消息传送出去。消息路由器会在接收客户机确认时进行记录，并且只有在接收到所有确认后才会删除 JMS 消息（除非在这之前 JMS 消息已过期）。

> 另外，消息路由器会将代理确认发送回客户机，确认已接收到客户机确认。使用方客户机使用代理确认来确保代理不会多次传送 JMS 消息（请参见“消息使用”）。如果由于某些原因使代理未能接收到客户机确认，则可能发生多次传送的情况。

> 如果代理没有接收到客户机确认并传送了 JMS 消息，此消息将被标注重新传送标志。通常，如果在代理接收到客户机确认之前客户机连接被关闭，并且随后又打开了新的连接，那么代理会重新传送 JMS 消息。例如，如果队列的消息使用方在确认消息之前脱机，随后另一位使用方向队列进行了注册，则代理会向该新使用方重新传送未确认的消息。

> 上述客户机和代理的确认过程同样适用于编组为事务的 JMS 消息传送。对于后者，客户机和代理确认在事务级别以及各个 JMS 消息发送或接收级别运行。当提交事务时，将自动发送代理确认。

> 代理会跟踪事务，使它们可以在出现故障时进行提交或回滚。该事务管理也支持本地事务（较大的分布式事务的一部分，请参见“分布式事务”）。代理会一直跟踪这些事务的状态，直到它们被提交。当代理启动时，它会检查所有未提交的事务，在默认情况下，回滚未处于 PREPARED 状态的所有事务。

> ##### 可靠传送：持久性

> 可靠传送的另一个方面是确保在实际传送消息前，代理没有丢失消息或要传送的信息。通常，消息将始终保留在内存中，直到被传送或过期。但如果代理出现故障，这些消息将会丢失。

> 生成方客户机可以将消息指定为持久性消息，在这种情况下，消息路由器会将此消息传送到持久性管理器，该管理器将把消息存储在数据库或文件系统中（请参见“持久性管理器”），这样即使代理出现故障，消息也可以得到恢复。

> ##### 管理内存资源和消息流

> 代理的性能和稳定性取决于可用的系统资源以及资源（如内存）的使用效率。特别是，当消息的生成大大快于使用时，消息路由器可能无法承受大量的消息，可能会用光其所有内存资源。为防止这种情况，消息路由器使用了三级内存保护以在资源不足时保持操作系统运转：

> 单个目标的消息限制 可设置物理目标的属性，指定消息数量的限制和消息使用的总内存限制（请参见表 6-10），也可设置在达到这些限制时，消息路由器将采取四种响应中的哪一种。四种限制行为为：

> - 减慢消息生成方
> - 丢弃内存中最旧的消息
> - 根据消息的生存期丢弃内存中优先级最低的消息
> - 拒绝最新的消息

> 系统范围消息限制 系统范围消息限制构成了第二道防线。可指定应用于系统中所有目标的系统范围限制：消息总数和所有消息占用的内存（请参见表 2-4）。如果达到了任何系统范围消息限制，消息路由器将拒绝新消息。

> 系统内存阈值 系统内存阈值是第三道防线。可指定可用系统内存的阈值，如果超过该阈值，代理可采取更为严格的操作，以此来防止内存过载。采取的操作取决于内存资源的状态：green（可用内存充足）、yellow（代理内存不足）、orange（代理内存严重不足）、red（代理无可用内存）。随着代理的内存状态由 green 变为 yellow，再变为 orange ，最后变为 red，代理所采取的措施也会越来越严格，操作类型如下：

> - 将消息从活动内存交换至持久性存储器（请参见“持久性管理器”）；通常可以将不存储的非持久性消息换出内存，以便系统回收内存
> - 限制非持久性消息的生成方，最后甚至会停止进入代理的消息流。（持久性消息流自动由代理确认的每条消息的要求限制）

> 这些措施都会降低性能。

> 如果达到系统内存的阈值，则说明没有适当地设置针对目标的消息限制以及系统范围消息限制。在某些情况下，阈值不可能及时地捕捉到潜在的内存过载。因此，您不应依赖此功能来控制内存资源，而应该分别配置目标，共同优化内存资源。

> ##### 消息路由器属性

> 有关管理内存资源的系统范围限制和系统内存阈值的详细信息，请参见表 2-4。（有关设置这些属性的说明，请参见第 5 章“启动与配置代理”。）

> 表 2-4 消息路由器属性

> 属性名称 | 说明
> --- | ---
> imq.message.expiration. interval | 指定过期消息的回收频率（以秒为单位）。 默认值： 60
> imq.system.max_count | 指定代理保留的消息的最大数量。附加消息将被拒绝。值 -1 表示没有限制。 默认值： -1
> imq.system.max_size | 指定代理保留的消息的最大总大小（以字节、千字节或兆字节为单位）。附加消息将被拒绝。值 -1 表示没有限制。 默认值： -1
> imq.message.max_size | 指定消息主体允许的最大大小（以字节、千字节或兆字节为单位）。任何大于此大小的消息将被拒绝。值 -1 表示没有限制。 默认值：70m（兆字节）
> imq.resource_state. threshold | 指定将触发各个内存资源状态的内存占用百分比。资源状态的值可以是 green、yellow、orange 和 red。 默认值：分别为 0、80、90 和 98
> imq.resource_state.count | 指定当触发各个内存资源状态时允许同时处理的一批外来消息的最大数量。当系统内存愈加不足时，此限制可限制消息的生成方。 默认值：分别为 5000、500、50 和 0
> imq.transaction. autorollback | 指定 (true/false) 当启动代理时，处于 PREPARED 状态的分布式事务是否自动回滚。如果为 false，则必须使用 imqcmd 手动提交或回滚事务（请参见“管理事务”）。 默认值：false

> #### 持久性管理器

> 对于发生故障后待恢复的代理，需要重新创建其消息传送操作的状态。这需要它将所有持久性消息以及基本的路由和传送信息保存到数据存储中。持久性管理器组件用于管理此信息的写入和检索。

> 为了恢复出现故障的代理，不仅需要恢复未传送的消息，代理还必须完成以下操作：

> - 重新创建目标
> - 恢复每个主题的长期订阅列表
> - 恢复每条消息的确认列表
> - 重新生成所有已提交事务的状态

> 持久性管理器用于管理所有这些状态信息的存储和检索。

> 当代理重新启动时，它将重新创建目标和长期订阅，恢复持久性消息和所有事务的状态，并重新创建未传送消息的路由表。然后代理才可以恢复消息传送。

> Message Queue 既支持内置的持久性模块，也支持插入的持久性模块（请参见图 2-4）。内置的持久性是基于文件的数据存储。插入的持久性使用 Java 数据库连接 (JDBC) 接口，并需要 JDBC 兼容的数据存储。通常，内置的持久性比插入的持久性速度更快，但某些用户更希望获得使用 JDBC 兼容的数据库系统的冗余和管理功能。

> 图 2-4 持久性管理器支持

> ##### 内置的持久性

> Message Queue 持久性存储器的默认解决方案是基于文件的数据存储。该解决方案使用单个文件来存储持久性数据，如消息、目标、长期订阅和事务等。

> 基于文件的数据存储位于由与数据存储相关联的代理实例的名称 (instanceName) 标识的目录内（请参见附录 A“Message Queue 数据的位置”）：

> …/instances/instanceName/fs350/

> 可构建基于文件的数据存储，以便持久性消息所在的目标将其保存在目录中。大多数消息存储在由大小可变的记录组成的单个文件中。

> 为减少添加和删除消息带来的碎片，可压缩大小可变的记录文件（请参见“压缩目标”）。另外，内置的持久性管理器可在其各自的文件中存储大小超过配置阈值 (imq.persist.file.message.max_record_size) 的消息，而不是存储在大小可变的记录文件中。对于这些单个文件，可维护文件池以便重新使用这些文件。当消息文件不再需要时，无需删除，可将其添加至目标目录的空闲文件池中，以便存储新的消息。

> 可配置目标文件池中文件的最大数量 (imq.persist.file.destination.message.filepool.limit) 并指定文件池中空闲文件所占的百分比 (imq.persist.file.message.filepool.cleanratio)，达到此百分比后将清除文件池（清空），而不是仅标记这些空闲文件供重复使用（不清空）。此清除文件的百分比越高，文件池所需的磁盘空间越小，但维护文件池所需的开销就越大。另外，也可以指定关闭时是否清除标记的文件 (imq.persist.file.message.cleanup)。如果清除这些文件，它们所占用的磁盘空间就会减少，但代理将需要更长的时间来进行关闭操作。

> 所有其他持久性数据（目标、长期订阅和事务）都存储在其自己的单独文件中：所有目标在一个文件中，所有长期订阅在另一个文件中，依此类推。

> 要使可靠性最大化，可指定 (imq.persist.file.sync.enabled) 持久性操作使用物理存储设备与内存中状态同步。这可帮助避免由于系统崩溃而导致的数据丢失，但会消耗一部分性能。

> 由于数据存储中可能包含敏感的或私有的消息，因此建议保护 instances/instanceName/fs350/ 目录，防止未授权就进行访问。有关说明，请参见“确保持久性数据的安全”。

> ##### 插入的持久性

> 您可以设置一个代理，以访问任何可通过 JDBC 驱动程序进行访问的数据存储。该过程涉及：设置多个与 JDBC 相关的代理配置属性、使用数据库管理器实用程序 (imqdbmgr) 来创建具有相应架构的数据存储。附录 B“设置插入的持久性” 中详细说明了上述过程以及相关的配置属性。

> ##### 持久性管理器属性

> 表 2-5 详细说明了与持久性相关的配置属性。（有关设置这些属性的说明，请参见第 5 章“启动与配置代理”。）

> 除第一个属性之外，表 2-5 中的所有属性都仅能用于内置持久性。与插入的持久性相关的属性在表 B-1 中。

> 表 2-5 持久性管理器属性

> 属性名称 | 说明
> --- | ---
> imq.persist.store | 指定代理是使用内置的、基于文件的 (file) 持久性，还是使用插入的、JDBC 兼容的 (jdbc) 持久性。 默认值：file
> imq.persist.file.sync. enabled | 指定持久性操作是否使内存中状态与物理存储设备同步。如果为 true，则可以避免由于系统崩溃导致的数据丢失，但持久性操作的性能会有所降低。 默认值：false
> imq.persist.file.message. max_record_size | 适用于内置的、基于文件的持久性，指定将添加到消息存储文件中的消息的最大大小（相对于存储在单独文件中的消息）。默认值：1m（兆字节）
> imq.persist.file. destination.message .filepool.limit | 适用于内置的、基于文件的持久性，指定目标文件池中可供重复使用的空闲文件的最大数量。该数量越大，代理处理持久性数据的速度越快。超过该值的空闲文件将被删除。代理将根据需要创建文件或删除超过此限制的文件。默认值： 100
> imq.persist.file.message. filepool.cleanratio | 适用于内置的、基于文件的持久性，指定保持清除状态（清空）的目标文件池中空闲文件的百分比。该值越大，在操作中清除文件所需的开销越大，但文件池所需的磁盘空间越小。 默认值： 0
> imq.persist.file.message. cleanup | 适用于内置的、基于文件的持久性，指定代理在关闭时是否清除目标文件池中的空闲文件。如果值为 false，则关闭代理的速度会加快，但文件存储需要的磁盘空间会更多。默认值：false

> #### 安全性管理器

> Message Queue 提供验证和授权（访问控制）功能，同时也支持加密功能。

> 验证和授权功能取决于用户信息库（请参见图 2-5）：包含消息传送系统的用户信息（用户名、密码和组成员资格）的文件、目录或数据库。用户名和密码用于在请求连接至代理时对用户进行验证。用户名和组成员资格（与访问控制文件配套使用）用于授权操作，例如为目标生成消息或使用目标的消息。

> Message Queue 管理员可填充 Message Queue 提供的用户信息库（请参见“使用文本文件用户信息库”），也可以将原有的 LDAP 用户信息库插入到安全性管理器组件中（请参见“使用 LDAP 服务器管理用户信息库”）。文本文件用户信息库使用起来较简单，但在安全性上也易遭攻击，因此应只将其用于测试和开发目的，而 LDAP 用户信息库相对较安全，因此更适合用于生产目的。

> ##### 验证

> Message Queue 安全性支持基于密码的验证。当客户机请求连接到代理时，该客户机必须提交用户名和密码。安全性管理器将把客户机提交的用户名和密码与用户信息库中存储的用户名和密码进行比较。密码在从客户机传送到代理的过程中，将使用 Base 64 编码或消息摘要 (MD5) 进行编码。要想获得更安全的传送，请参见“加密（企业版）”。可以分别配置每个连接服务使用的编码的类型，也可以基于代理范围设置编码方式。

> ##### 授权

> 客户机应用程序的用户通过验证后，即可以获得授权来执行各种 Message Queue 相关的活动。安全性管理器既支持基于用户的访问控制，也支持基于组的访问控制：根据用户在用户信息库中分配到的用户名或组的不同，该用户所拥有的执行特定 Message Queue 操作的权限也不同。这些访问控制在访问控制属性文件中指定（请参见图 2-5）。

> 当用户尝试执行某个操作时，安全性管理器将检查该用户的用户名和组成员资格（通过用户信息库）是否属于被指定允许访问该操作的用户名或组成员资格（在访问控制属性文件中）。访问控制属性文件指定了执行以下操作的权限：

> - 建立与代理的连接
> - 访问目标：创建任意给定目标或所有目标的使用方、生成方或队列浏览器
> - 自动创建目标

> 图 2-5 安全性管理器支持

> 默认的访问控制属性文件只明确引用一个组：管理员（请参见“组”）。管理员组中的用户拥有管理服务连接权限。管理服务使用户可以执行管理功能，如创建目标以及监视和控制代理。默认情况下，您定义的其他任何组中的用户都无法获得管理服务连接。

> 作为 Message Queue 管理员，可以在用户信息库中定义组并使用户与这些组关联（虽然在文本文件用户信息库中不完全支持组）。然后，通过编辑访问控制属性文件，可以按照用户和组的不同目的（生成和使用消息，或浏览队列目标中的消息）指定对目标的权限。可以分别指定各个目标或指定所有目标仅能够被特定用户或组访问。

> 另外，如果将代理配置为允许自动创建目标（请参见“自动创建的（与管理员创建的相对）目标”），则可以通过编辑访问控制属性文件来控制代理可为谁自动创建目标。

> ##### 加密（企业版）

> 要对客户机和代理之间发送的消息进行加密，需要使用基于安全套接字层 (SSL) 标准的连接服务。SSL 通过在启用 SSL 的代理与启用 SSL 的客户机之间建立加密连接来提供连接级别的安全性。

> 为了使用 Message Queue 基于 SSL 的连接服务，需要使用密钥工具实用程序 (imqkeytool) 生成专用密钥/公用密钥对。此实用程序将公用密钥嵌入自签名的证书中，并将其放入 Message Queue 密钥存储中。Message Queue 密钥存储本身设有密码保护，要解除锁定，需要在启动时提供密钥存储的密码。请参见“加密：使用基于 SSL 的服务（企业版）”。

> 解除密钥存储的锁定后，代理即可将证书传送给所有请求连接的客户机。然后，客户机使用此证书建立与代理的加密连接。

> 表 2-6 所示为验证、授权、加密以及其他安全性通信的可配置属性。（有关配置这些属性的说明，请参见第 5 章“启动与配置代理”）

> 表 2-6 安全性管理器属性

> 属性名称 | 说明
> --- | ---
> imq.authentication.type | 指定传送密码时应使用 Base 64 编码 (basic) 还是 MD5 摘要 (digest)。设置代理支持的所有连接服务的编码。 默认值：digest
> imq.service_name. authentication.type | 指定传送密码时应使用 Base 64 编码 (basic) 还是 MD5 摘要 (digest)。设置命名的连接服务的编码，此设置将覆盖任意代理范围的设置。 默认值：继承 imq.authentication.type 的值
> imq.authentication. basic.user_repository | 对于 Base 64 编码，指定用于验证的用户信息库的类型：基于文件 (file) 或 LDAP (ldap)。有关其他 LDAP 属性，请参见表 8-5。 默认值：file
> imq.authentication. client.response.timeout | 指定系统等待客户机响应来自代理的验证请求的时间（以秒为单位）。 默认值：180（秒）
> imq.accesscontrol. enabled | 为代理支持的所有连接服务设置访问控制 (true/false)。表明系统是否要检查已验证的用户是否如访问控制属性文件所指定，拥有使用连接服务或执行与特定目标有关的特定 Message Queue 操作的权限。 默认值：true
> imq.service_name. accesscontrol.enabled | 为命名的连接服务设置访问控制 (true/false)，此设置将覆盖代理范围的设置。表明系统是否要检查已验证的用户是否如访问控制属性文件所指定，拥有使用连接服务或执行与特定目标有关的特定 Message Queue 操作的权限。 默认值：继承 imq.accesscontrol.enabled 的值
> imq.accesscontrol.file. filename | 为代理实例支持的所有连接服务指定访问控制属性文件的名称。文件名称指定访问控制目录的相对文件路径（请参见附录 A“Message Queue 数据的位置”）。 默认值：accesscontrol.properties
> imq.service_name. accesscontrol.file.filename | 为代理实例的命名连接服务指定访问控制属性文件的名称。文件名称指定访问控制目录的相对文件路径（请参见附录 A“Message Queue 数据的位置”）。 默认值： 继承 imq.accesscontrol.file.filename 的值。
> imq.passfile.enabled | 指定 (true/false) 是否在密码文件中指定用于安全性通信的用户密码（适用于 SSL、LDAP 和 JDBC™) 默认值：false
> imq.passfile.dirpath | 指定包含密码文件的目录的路径（根据操作系统）。 默认值：请参见附录 A“Message Queue 数据的位置”
> imq.passfile.name | 指定密码文件的名称。 默认值：密码文件
> imq.keystore.property_name | 适用于基于 SSL 的服务：指定与 SSL 密钥存储相关的安全性属性。请参见表 8-8。

> #### 监视服务

> 代理包含大量用于监视和诊断其操作的组件。包括：

> - 生成数据的组件（记录事件的代理代码和度量依据生成器）
> - 通过多种输出通道记录输出信息的日志记录器组件（请参见“日志记录器”）
> - 将包含度量依据信息的 JMS 消息发送到主题目标供 JMS 监视客户机使用的消息生成方。

> 图 2-6 中是通用方案的图解。

> 图 2-6 监视服务支持

> ##### 度量依据生成器

> 度量依据生成器提供有关代理活动的信息，如流入、流出代理的消息、代理内存中的消息数量及其使用的内存量、打开的连接数量和正在使用的线程数量。

> 可以打开或关闭度量依据数据的生成，并指定生成度量依据报告的频率。

> ##### 日志记录器

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

> 可指定日志记录器收集的信息类型，以及写入每个输出通道的类型。

> 例如，可以指定日志记录器级别（日志记录器收集的信息类型）：从最严重和最重要的信息（错误）到次要信息（度量依据数据）。表 2-7 所示为信息的种类（按重要性的降序排列）：

> 表 2-7 日志种类

> 种类 | 说明
> --- | ---
> ERROR | 指出可能导致系统故障的问题的消息。
> WARNING | 需要注意但不会导致系统故障的警报。
> INFO | 度量依据及其他信息性消息的报告。

> 要设置日志记录器级别，需要指定其中的某个种类。日志记录器将记录指定种类及所有更高级别种类的数据。例如，如果指定记录 WARNING 级别的信息，则日志记录器将记录警告信息和错误信息。

> 可以分别指定写入到每个输出通道的日志记录器的种类集。例如，如果将日志记录器级别设置为 INFO，则可以指定只将错误和警告写入控制台，只将信息（度量依据数据）写入日志文件。（有关配置和使用 Solaris syslog 的信息，请参见 syslog(1M)、syslog.conf(4) 和 syslog(3C) 手册页。）

> 对于日志文件，还可以指定何时关闭日志文件并将输入转移到新文件。在日志文件达到指定的大小或生存期后，将保存该文件并创建一个新的日志文件。日志文件写入一个目录中，该目录用与日志文件相关联的代理实例的名称 (instanceName) 标识（请参见附录 A“Message Queue 数据的位置”）：

> /instances/instanceName/log/

> 创建新的转移日志文件时，将保留最新的 9 个日志文件的归档文件。

> 有关配置日志记录器的信息，请参见表 2-9 和“更改日志记录器配置”。

> ##### 度量依据消息生成方（企业版）

> 消息生成方组件按一定的时间间隔接收度量依据生成器的信息，并将信息写入消息中，然后根据消息中包含的度量依据信息类型，将消息发送至多个度量依据主题目标之一。

> 共有五种度量依据主题目标，其名称显示在表 2-8 中，其中还有传送到每个目标的度量依据消息类型。

> 表 2-8 度量依据主题目标

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

> 这些度量依据主题目标订阅的 Message Queue 客户机使用目标中的消息，并处理消息中包含的度量依据信息。例如，客户机可订阅 mq.metrics.broker 目标以接收和处理诸如代理中消息总数的信息。

> 度量依据消息生成方是一个内部 Message Queue 客户机，可创建包含与度量依据数据相对应的名称值对的消息（类型为 MapMessage）。仅当相应的度量依据主题目标有一个或多个订阅者时，才生成这些消息。

> 度量依据消息生成方生成的消息类型为 MapMessage；取决于其包含的度量依据类型，它会由很多名称/值对组成。每个名称/值对与度量依据数量及其值相对应。例如，代理度量依据消息包含多个度量依据数量的值，包括流入和流出代理的消息数量，当前在内存中的消息数量和大小，等等。有关每种类型的度量依据消息报告的度量依据数量的详细信息，请参见《Message Queue Java Client Developer's Guide 》，其中介绍了如何写入使用度量依据消息的 Message Queue 客户机。

> 除了包含在度量依据消息主体中的度量依据信息之外，每条消息的标题有两个属性：一个指定度量依据消息类型，一个记录时间戳。这些标题属性可由 Message Queue 客户机应用程序用于从度量依据消息中提取数据，并记录其相应的时间戳。

> ##### 监视服务属性

> 表 2-9 所示为用于通过代理设置信息的生成、记录和度量依据消息生成的可配置属性。（有关配置这些属性的说明，请参见第 5 章“启动与配置代理”）

> 表 2-9 监视服务属性

> 属性名称 | 说明
> --- | ---
> imq.metrics.enabled | 指定 (true/false) 是否要将度量依据信息写入日志记录器。不影响度量依据消息的生成（请参见 imq.metrics.topic.enabled）。 默认值：true
> imq.metrics.interval | 如果启用了度量依据记录 (imq.metrics.enabled=true)，指定将度量依据信息写入日志记录器的时间间隔（以秒为单位）。值-1 表示从不。不影响度量依据消息的生成时间间隔（请参见 imq.metrics.topic.interval）。 默认值： -1
> imq.log.level | 指定日志记录器级别：可以写入到输出通道的输出的种类。包括指定的种类以及所有更高级别的种类。值分别为（由高至低）：ERROR、WARNING 和 INFO。 默认值：INFO
> imq.log.file.output | 指定写入到日志文件的日志记录信息的种类。允许的值为：由竖线 (|) 分隔的任意日志记录种类集，或 ALL 和 NONE。 默认值：ALL
> imq.log.file.dirpath | 指定包含日志文件的目录的路径（根据操作系统）。 默认值：请参见附录 A“Message Queue 数据的位置”
> imq.log.file.filename | 指定日志文件的名称。 默认值：log.txt
> imq.log.file.rolloverbytes | 指定日志文件的大小（以字节为单位），达到该大小后输出将转移到新的日志文件。值 -1 表示不进行基于文件大小的转移。 默认值：-1
> imq.log.file.rolloversecs | 指定日志文件的生存期（以秒为单位），达到该值后输出将转移到新的日志文件。值 -1 表示不进行基于文件生存期的转移。 默认值：604800（一周）
> imq.log.console.output | 指定将哪些种类的日志记录信息写入到控制台。允许的值为：由竖线 (|) 分隔的任意日志记录种类集，或 ALL 和 NONE。 默认值：ERROR| WARNING
> imq.log.console.stream | 指定是否将控制台输出写入到标准输出 (OUT) 或标准错误 (ERR)。 默认值：ERR
> imq.log.syslog.facility | （仅对于 Solaris）指定 Message Queue 代理应将 syslog 记录为哪种系统日志工具。属性值镜像 syslog(3C) 手册页中列出的值。适用于 Message Queue 的值包括：LOG_USER、LOG_DAEMON 和 LOG_LOCAL0 到 LOG_LOCAL7。 默认值：LOG_DAEMON
> imq.log.syslog.logpid | （仅对于 Solaris）指定 (true/false) 是否将代理进程 ID 与消息一起记录。 默认值：true
> imq.log.syslog.logconsole | （仅对于 Solaris）指定 (true/false) 如果无法将消息发送到 syslog，是否将其写入到系统控制台。 默认值：false
> imq.log.syslog.identity | （仅对于 Solaris）此属性指定的标识字符串应添加到每个记录到 syslog 的消息的前面。 默认值：imqbrokerd_代理实例名称。
> imq.log.syslog.output | （仅对于 Solaris）指定将哪些种类的日志记录信息写入到 syslogd(1M)。允许的值为：由竖线 (|) 分隔的任意日志记录种类，或 ALL 和 NONE。 默认值：ERROR
> imq.log.timezone | 指定日志时间戳的时区。标识符与 java.util.TimeZone.getTimeZone() 使用的一致。 例如：GMT、America/LosAngeles、Europe/Rome 和 Asia/Tokyo。 默认值：本地时区
> imq.metrics.topic.enabled | 指定 (true/false) 是否启用度量依据消息生成。如果为 false，则试图订阅度量依据主题目标时会抛出客户端异常。 默认值：true
> imq.metrics.topic.interval | 指定生成度量依据消息（发送到度量依据主题目标）的时间间隔（以秒为单位）。 默认值： 60
> imq.metrics.topic.persist | 指定 (true/false) 度量依据消息是否为持久性。 默认值：false
> imq.metrics.topic.timetolive | 指定生成度量依据消息（发送到度量依据主题目标）的生命周期（以秒为单位）。 默认值： 300

> ### 物理目标

> Message Queue 消息传送基于两个传送阶段：首先，消息从生成方客户机传送到代理上的目标，然后再从代理上的目标传送到一个或多个使用方客户机。目标分两种类型（请参见“编程域”）：队列（点对点传送模型）和主题（发布/订阅传送模型）。这些目标表示代理的物理内存中的位置（外来消息在被路由到使用方客户机前将保留在其中）。

> 可以使用 Message Queue 管理工具创建物理目标（请参见“获得连接信息”）。也可以按照“自动创建的（与管理员创建的相对）目标”中的介绍来自动创建目标。

> 本节介绍这两种类型的物理目标（队列和主题）的属性和行为。

> #### 队列目标

> 队列目标用于点对点消息传送。在这种消息传送中，会有多个使用方在目标中注册请求，但消息最终仅传送到其中的一个使用方。当来自消息生成方的消息到达时，它们将排成队列的形式，然后发送到单个消息使用方。

> ##### 多个使用方的队列传送

> 当队列目标中的任何消息仅传送到单个使用方时，Message Queue 允许多个使用方向队列注册。代理会将外来消息路由至其他使用方，在使用方中平衡负荷。

> 对多个使用方的队列传送的实现是根据以下队列目标属性使用可配置的负荷平衡的方法：

> - maxNumActiveConsumers:指定在负荷平衡队列传送中活动的使用方的数量（一个或多个）
> - maxNumBackupConsumers:指定当任何活动使用方失败时可代替活动使用方的备份使用方的数量（无或多个）。

> 如果使用方数量超过这两个属性的和，将拒绝新的使用方。(Message Queue 平台版支持每个队列多达 3 个使用方（2 个活动和 1 个备份），而Message Queue 企业版支持无限个使用方。）

> 负荷平衡机制考虑了不同使用方的消息使用率。其工作方式如下：

> 队列目标中的消息按可配置大小的批次（队列目标的 consumerFlowLimit 属性）路由至新的可用活动使用方（以便向队列注册）。这些消息传送之后，其他到达此队列的消息将在使用方可用时（即，当使用方先前已使用了传送给他们的可配置百分比的消息）按批次路由至使用方。每个使用方的发送率取决于使用方的当前容量和消息处理速率。

> 当消息生成速率较低时，代理可在活动使用方之间不平衡地发送消息。如果活动使用方多于所需个数，其中的一些可能永远收不到消息。

> 如果活动使用方失败，则第一个备份使用方变为活动，并取代失败使用方的任务。当队列目标中有多于一个活动使用方时，消息使用的顺序是不一定的。

> 在代理群集环境中，对多个使用方的传送可设置为优先考虑本地使用方。队列目标属性 localDeliveryPreferred 使您可指定仅当生成方的主代理（即，生成方将消息发送到的代理，本地代理）中无使用方时，才将消息传送到远程使用方。这可在路由到远程使用方（通过其主代理）可能导致流通量降低时提升性能。（此属性需要目标范围未限制为仅本地传送。请参见表 6-10。）

> ##### 内存的注意事项

> 由于消息可以在队列中保留相当长的一段时间，因此内存资源可能会成为一个问题。为队列分配内存时，您一定希望分配得恰到好处，向一个队列分配过多内存会导致内存不足，而太少的话消息就会被拒绝。出于灵活性的考虑，可以基于每个队列的负荷要求在创建队列时设置物理属性：队列消息的最大数量、分配给队列消息的最大内存和队列消息的最大大小（请参见表 6-10）。

> #### 主题目标

> 主题目标用于发布/订阅消息传送，在该消息传送中，消息最终将被传送到所有在目标中注册请求的使用方。当来自生成方的消息到达时，它们将被路由到所有订阅该主题的使用方。如果使用方已注册为长期订阅该主题，则当消息被传送到主题时并不需要这些使用方必须处于活动状态。代理将存储此消息，直到使用方再次处于活动状态，然后将消息传送给它。

> 通常，消息不会在主题目标中保留过长的时间，因此，内存资源通常也不是大问题。不过，您可以为目标收到的任意消息配置允许的最大大小（请参见表 6-10）。

> #### 自动创建的（与管理员创建的相对）目标

> Message Queue 消息服务器是消息传送系统的核心，因此其性能和可靠性对企业应用程序的正常运行至关重要。因为目标可能使用大量的资源（取决于它们处理的消息的数量和大小以及注册的消息使用方的数量和长期性），所以需要对它们严格地进行管理，以确保消息服务器的性能和可靠性。因此为应用程序创建目标、监视目标以及根据需要重新配置它们的资源要求已成为管理员的标准做法。

> 不过，有些时候可能需要动态创建目标。例如，在开发和测试阶段，可能希望代理根据需要自动创建目标，而不需要管理员进行干预。

> Message Queue 支持这种自动创建功能。启用自动创建后，每当 MessageConsumer 或 MessageProducer 尝试访问不存在的目标时，代理会自动创建一个目标。（客户机应用程序的用户必须拥有自动创建特权，请参见“目标自动创建访问控制”。）

> 不过，当自动（而非明确）创建目标时，可能会导致不同客户机应用程序（使用相同的目标名称）之间发生冲突，或者导致系统性能降低（由于支持目标需要使用资源）。因此，当不再使用自动创建的目标时，也就是当目标不再与消息使用方客户机保持连接且不再包含任何消息时，代理会自动将其销毁。重新启动代理后，只有当自动创建的目标包含持久性消息时，才会重新创建这些目标。

> 可以使用表 2-10 中所示的属性来配置 Message Queue 消息服务器，以便启用或禁用自动创建功能。（有关配置这些属性的说明，请参见第 5 章“启动与配置代理”）

> 表 2-10 自动创建配置属性

> 属性名称 | 说明
> --- | ---
> imq.autocreate.topic | 指定 (true/false) 是否允许代理自动创建主题目标。 默认值：true
> imq.autocreate.queue | 指定 (true/false) 是否允许代理自动创建队列目标。 默认值：true
> imq.autocreate.destination. maxNumMsgs | 指定自动创建的目标中允许的未使用消息的最大数量。 默认值： 100,000
> imq.autocreate.destination. maxTotalMsgBytes | 指定目标中允许的内存的最大总量（以字节为单位）。 默认值：10m（兆字节）
> imq.autocreate.destination. limitBehavior | 指定当达到内存限制的阈值时代理响应的方式。允许的值为： FLOW_CONTROL－减慢生成方 REMOVE_OLDEST－丢弃最旧的消息 REMOVE_LOW_PRIORITY－根据消息的生存期丢弃优先级最低的消息 REJECT_NEWEST－拒绝最新的消息 默认值：REJECT_NEWEST
> imq.autocreate.destination. maxBytesPerMsg | 指定自动创建的目标中允许的任何单个消息的最大大小（以字节为单位）。 默认值：10k (10,240)
> imq.autocreate.destination. maxNumProducers | 指定目标允许的生成方的最大数量。当达到此限制时，将无法创建新的生成方。 默认值： 100
> imq.autocreate.destination. isLocalOnly | 仅适用于代理群集。指定目标不能在其他代理上复制，因而将消息传送限制为本地使用方（连接到创建目标的代理的使用方）。在创建目标之后此属性无法更新。 默认值：false
> imq.autocreate.queue. maxNumActiveConsumers | 指定在从自动创建的队列目标的负荷平衡传送中可以处于活动状态的最大使用方数。值为 -1 表示不限制数量。 默认值： 1
> imq.autocreate.queue. maxNumBackupConsumers | 指定在从自动创建的队列目标的负荷平衡传送期间出现任何错误时，可以代替这些活动使用方的最大备份使用方的数量。值为 -1 表示不限制数量。 默认值： 0
> imq.autocreate.queue. consumerFlowLimit | 指定将要在一批中传送给使用方的消息的最大数量。在负荷平衡队列传送中，为负荷平衡开始之前路由至活动使用方的队列消息的初始数量（请参见“多个使用方的队列传送”）。此限制可被为目标使用方在其各自的连接中设置的较低的值覆盖（请参见《Message Queue Java Client Developer's Guide》中的连接工厂属性中的信息）。值为 -1 表示不限制数量。 默认值： 1000
> imq.autocreate.topic. consumerFlowLimit | 指定将要在一批中传送给使用方的消息的最大数量。值为 -1 表示不限制数量。 默认值： 1,000
> imq.autocreate.queue. localDeliveryPreferred | 仅应用于代理群集中的负荷平衡队列传送。指定仅当在本地代理中没有使用方时才将消息传送到远程的使用方。要求未将自动创建的目标限制为仅本地传送 (isLocalOnly = false)。 默认值：false

> #### 临时目标

> 某些客户机需要一个目标来接收对发送至其他客户机的消息的回复。这些客户机使用 JMS API 明确创建和销毁的目标称为临时目标。这些目标是为连接而创建的，并由代理维护，而且仅在连接期间存在。临时目标无法由管理员销毁，而且只要此目标在使用中（即连接有活动的消息使用方），那么它也无法由客户机应用程序销毁。临时目标与管理员创建或自动创建的目标不同（后两者包含持久性消息），它们不会被持久保存，并且在重新启动代理时也不会重新创建临时目标，但是，可通过 Message Queue 管理工具看到这些内容（请参见表 6-9）。

> ### 多代理群集（企业版）

> Message Queue 企业版使用多个互连的代理实例（代理群集）来支持消息服务器的实现方案。群集支持为消息服务器提供了可伸缩性。

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

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

> 虽然使用代理群集还有其他原因（例如，适应具有不同用户信息库的工作组或处理防火墙限制），但故障转移并不是其中的一个原因。当 Message Queue 允许失败的连接使用群集中的其他代理重新建立连接时，将丢失状态信息。因此，群集中的某个代理不能用作其他发生故障的代理的自动备份。

> 换言之，Message Queue 目前不支持高可用性消息服务器。但是，您可以使用 Sun Cluster 软件和高可用性数据库提供代理故障转移。也可以将消息传送应用程序设计为使用多个代理来实现自定义的故障转移解决方案。

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

> 以下几个小节介绍了 Message Queue 代理群集的体系结构和内部功能。

> #### 多代理体系结构

> 多代理消息服务器允许将客户机连接分布在多个代理实例上，如图 2-7 中所示。从客户机的角度来看，每个客户机都连接到各自的代理（其主代理），发送和接收消息时就好像主代理是群集中唯一的代理。但从消息服务器的角度来看，主代理与群集中的其他代理串联起来进行工作，为主代理直接连接的消息生成方和使用方提供传送服务。

> 理论上，群集中的代理可以以任意拓扑结构连接。但 Message Queue 仅支持完全连接的群集，即在该拓扑结构中，每个代理都与群集中的其他所有代理直接连接，如图 2-7 所示。

> 图 2-7 多代理（群集）体系结构

> ##### 消息传送

> 在多代理配置中，每个目标复制于群集中的所有代理上。（在大多数情况下，群集环境中的目标属性通常共同应用于目标的所有实例，即，应用于整个群集，而不是应用于单个目标实例。同时，isLocalOnly 属性设置为 true 的目标不会在群集中复制。有关详细信息，请参见表 6-10 中有关目标属性的说明。）

> 每个代理都了解向所有其他代理的目标进行注册的消息使用方。因此，每个代理既可以将消息从其直接连接的消息生成方路由到远程消息使用方，也可以从远程生成方将消息发送到其直接连接的使用方。

> 在群集配置中，与每个消息生成方直接连接的代理将对该直接相连的生成方发送给它的消息执行路由。因此，持久性消息是通过消息的主代理进行存储和路由的。

> 要使群集中的代理之间的流量最小化，可通过使用方连接上的流控制机制来管理消息的传送（从目标到客户机运行时）。按这种方式，仅在代理要把消息传送给连接到目标代理上的使用方时，才把消息从一个代理发送到另一个代理，从而避免了代理之间不必要的消息传递。同时，在某些情况下（例如，到多个使用方的队列传送），可以指定到本地使用方的传送的优先级大于传送到远程使用方的优先级，从而使代理之间的流量最小化（请参见 localDeliveryPreferred 队列目标属性，表 6-10）。

> 当需要客户机和消息服务器之间的安全加密消息传送时，可将群集配置为同时保护群集中的代理之间的消息传送（请参见“安全的交叉代理连接”）。

> ##### 群集同步

> 当管理员创建或销毁代理上的目标时，此信息会自动传播到群集中其他所有代理。同样，当消息使用方向其主代理进行注册，或当使用方与其主代理断开连接（无论是明确断开，还是因为客户机、网络故障或其主代理故障而断开），该使用方的相关信息都会被传播到整个群集。与此类似，长期订阅的相关信息也会被传播到群集中的所有代理。

> 注意 | 网络繁忙和/或消息较大可能会堵塞内部群集连接。该不断增加的延迟有时还会引起锁定协议超时错误。这样，客户机在尝试创建长期订阅者或将消息使用方排队时可能会引发异常。通常，使用高速连接可以避免这些问题。

> 将目标和消息使用方的相关信息传播至特定代理时，通常要求在共享资源中进行更改时该代理处于联机状态。如果进行这样的更改时代理处于脱机状态，那么将会发生怎样的情况呢（例如，代理崩溃、随后又重新启动，或者新代理被动态添加到群集）？

> 为了解决脱机的代理（或添加的新代理）带来的问题，Message Queue 会提供一份记录，其中包括对群集中所有持久性实体的更改，即所有已创建或已销毁的目标和长期订阅的记录。代理被动态添加到群集后，首先从此配置更改记录中读取目标和长期订阅者信息，当它进入联机状态后，将与其他代理交换当前活动使用方的相关信息。通过这些信息，新的代理将完全集成到群集中。

> 配置更改记录由群集中的一个代理（即指定为主管代理的代理）进行管理。因为主管代理是向群集动态添加代理的关键，所以应始终先启动此代理。如果主管代理未联机，则群集中的其他代理将无法完成初始化。

> 如果主管代理脱机，而其他代理又无法访问配置更改记录，则 Message Queue 将不允许在群集中传播目标和长期订阅。此时，如果尝试创建或销毁目标和长期订阅（或尝试大量相关操作，如重新激活长期订阅），将引发异常。

> 在关键任务的应用程序环境中，最好定期备份配置更改记录，以避免因记录意外损坏或主管代理故障带来的损失。可以使用 imqbrokerd 命令的 -backup 选项（此选项用于创建包含配置更改记录的备份文件，请参见表 5-2）来完成上述备份。然后可以使用 -restore 选项来恢复配置更改记录。

> 如果需要，可以更改用作主管代理的代理，更改方法为：备份配置更改记录，修改相应的群集配置属性（请参见表 5-3）以指定新的主管代理，然后使用 -restore 选项重新启动新的主管代理。

> #### 在开发环境中使用群集

> 在开发环境中，群集用于测试，而且可伸缩性和代理恢复不是很重要，因此基本不需要主管代理。在配置为没有主代理的环境中，Message Queue 不再要求必须运行主管代理才能启动其他代理，并允许对目标和长期订阅进行更改，并且可以在群集的所有运行代理中传播更改。如果代理脱机、随后又恢复，它将不会与脱机期间所作的更改同步。

> 在测试环境下，通常自动创建目标（请参见“自动创建的（与管理员创建的相对）目标”），并且由正在测试的应用程序创建和销毁这些目标的长期订阅。目标和长期订阅中的这些更改将在整个群集中传播。但是，如果将环境重新配置为使用主管代理，则 Message Queue 将重新强制要求必须运行主管代理才能更改目标和长期订阅并在整个群集中传播这些更改。

> #### 群集配置属性

> 启动时，群集中的每个代理都必须接收到有关群集中其他代理的信息（主机名和端口号）。此信息用于在群集中的代理之间建立连接。另外，每个代理也必须知道主管代理（如果使用）的主机名和端口号。

> 群集中的所有代理应使用共同的群集配置属性集。为此，可以将它们放入一个中心群集配置文件，启动时每个代理均会引用该文件。

> 也可以复制群集配置属性，然后分别为每个代理提供这些属性。但最好不要采用这种做法，因为这会导致群集配置中出现不一致。只保留一份群集配置属性可以确保所有代理获得相同的信息。

> 有关群集配置属性的详细信息，请参见“使用群集（企业版）”。

> 群集配置文件可以用于存储一组代理通用的所有代理配置属性。虽然，它原本是用来配置群集的，但也可以用来存储群集中所有代理通用的其他代理属性。

> ##

> Message Queue 客户机运行时

> Message Queue 客户机运行时向客户机应用程序提供至 Message Queue 消息服务的接口，即向 Java 客户机应用程序提供“JMS 编程模型”和具有相应的 C 接口的 C 客户机应用程序中介绍的所有 JMS 编程对象。Message Queue 客户机运行时支持客户机向目标发送消息以及从目标接收消息所需的所有操作。

> 本节提供 Message Queue 客户机运行时的工作方式的高级说明。影响客户机应用程序设计、Java 客户机运行时和 C 客户机运行时的性能的因素在《Message Queue Java Client Developer's Guide》和《Message Queue C Client Developer's Guide》中分别进行探讨。

> 图 2-8 说明了在消息的生成和使用中客户机应用程序如何与 Message Queue 客户机运行时之间进行交互以及在消息传送中 Message Queue 客户机运行时如何与 Message Queue 消息服务器之间进行交互。

> 图 2-8 消息传送操作

> ### 消息生成

> 在消息生成中，由客户机创建消息，然后通过连接将消息发送至代理中的目标。如果将 MessageProducer 对象的消息传送模式设置为持久性（有保证的传送，传送一次且仅传送一次），客户机线程将阻塞，直到代理确认消息已传送到其目标并存储在代理的持久性数据存储中为止。如果消息不是持久性的，则代理不会返回代理确认消息（在属性名称中称为 Ack），并且客户机线程不会阻塞。

> ### 消息使用

> 消息的使用要比生成复杂得多。在以下条件下，将把到达代理中的目标的消息通过连接传送到 Message Queue 客户机运行时：

> - 客户机已经设置了给定目标的使用方
> - 使用方的选择条件（如果存在）与到达给定目标的消息的选择条件匹配
> - 已告知连接开始传送消息。

> 通过连接传送的消息将分发到相应的 Message Queue 会话，在这些会话中，它们排队等待供相应的 MessageConsumer 对象使用，如图 2-9 所示。每次从每个会话队列中取出一条消息（会话是单线程的），然后同步使用（通过调用 receive 方法的客户机线程）或异步使用（通过调用 MessageListener 对象的 onMessage 方法的客户机线程）消息。

> 图 2-9 将消息传送到 Message Queue 客户机运行时

> 代理在向客户机运行时传送消息时，会对消息进行相应地标记，但无法实际得知这些消息是否已被接收或使用。因此，只有客户机确认接收到消息后，代理才会将消息从其目标中删除。

> ##

> Message Queue 受管理对象

> 受管理对象可以使客户机应用程序代码与提供者无关。为此，它们需要将提供者特有的实现方案和配置信息封装在对象中，而客户机应用程序可以通过与提供者无关的方式使用这些对象。受管理对象由管理员创建和配置，并存储在命名服务中，由客户机应用程序通过标准 JNDI 查找代码来访问。

> Message Queue 提供两种类型的受管理对象：ConnectionFactory 和 Destination。虽然两者都用于封存提供者特有的信息，但在客户机应用程序中，它们的用途却有很大的差异。ConnectionFactory 对象用于创建至消息服务器的连接，而 Destination 对象用于标识物理目标。

> 通过受管理对象，可以非常容易地控制和管理 Message Queue 消息服务器：

> - 您可以通过要求客户机应用程序访问预配置的 ConnectionFactory 对象来控制连接的行为（请参见“连接工厂受管理对象属性”）。
> - 您可以通过要求客户机应用程序访问与现有物理目标对应的预配置 Destination 对象来控制物理目标的创建。（您还需要禁用代理的自动创建功能，请参见“自动创建的（与管理员创建的相对）目标”。）
> - 您可以通过覆盖由客户机应用程序设置的消息标题值来控制 Message Queue 消息服务器资源（请参见“连接工厂受管理对象属性”）。

> 因此，受管理对象使您（Message Queue 管理员）可以控制消息服务器配置的详细信息，同时又可以使客户机应用程序与提供者无关：它们不需要了解提供者特有的语法和对象命名惯例（请参见“JMS 提供者无关”）或提供者特有的配置属性。

> 您可以使用 Message Queue 管理工具创建受管理对象，如第 7 章“管理受管理对象”中所述。创建受管理对象时，可以将对象指定为只读，也就是说，不允许客户机应用程序更改 Message Queue 特有的配置值（即在创建对象时设置的值）。换句话说，客户机代码无法设置只读受管理对象的属性值，而且也无法使用客户机应用程序的启动选项覆盖这些值，如“在客户机启动时覆盖属性值”中所述。

> 虽然客户机应用程序可以独立地实例化 ConnectionFactory 和 Destination 这两种受管理对象，但这样会削弱受管理对象的基本用途（即使 Message Queue 管理员可以控制应用程序所需的代理资源以及调整其性能的用途）。另外，直接实例化受管理对象将使客户机应用程序成为提供者特有的应用程序，而无法实现与提供者无关。

> ### 连接工厂受管理对象

> ConnectionFactory 对象用于建立客户机应用程序与 Message Queue 消息服务器之间的物理连接，还可用于指定连接的行为以及使用此连接访问代理的客户机运行时的行为。

> 如果要支持分布式事务（请参见“本地事务”），需要使用支持分布式事务的特殊的 XAConnectionFactory 对象。

> 要创建 ConnectionFactory 受管理对象，请参见“添加连接工厂”。

> 通过配置 ConnectionFactory 受管理对象，可以指定该对象生成的所有连接通用的属性值（属性）。ConnectionFactory 和 XAConnectionFactory 对象共享同一属性集。按照其影响的行为，这些属性可分为多个种类：

> - 连接规范
> - 自动重新连接行为
> - 客户机标识
> - 消息标题覆盖
> - 可靠性和流控制
> - 队列浏览器行为
> - 应用程序服务器支持
> - JMS 定义的属性支持

> 每个种类及其相应属性将在《Message Queue Java Client Developer's Guide》中进一步讨论。虽然作为 Message Queue 管理员，可能会要求您调整这些属性的值，但通常是由应用程序开发者来决定需要调整哪些属性以调节客户机应用程序的性能。表 7-3 按字母顺序概述了这些属性。

> ### 目标受管理对象

> Destination 受管理对象表示代理中与公开命名的 Destination 对象对应的物理目标（队列或主题）。表 2-11 中列出了它的两个属性。通过创建 Destination 对象，可以使客户机应用程序的 MessageConsumer 和/或 MessageProducer 对象能够访问相应的物理目标。

> 要创建 Destination 受管理对象，请参见“添加主题或队列”。

> 表 2-11 目标属性

> 属性/属性名 | 说明
> --- | ---
> imqDestinationName | 指定物理目标的供应商特有的名称。在创建物理目标时指定此名称。目标名称必须只包含字母数字字符（不包括空格），可以以字母字符或 _ 和 $ 字符开头。它们不能以字符串 mq. 开头。默认值：Untitled_Destination_Object
> imqDestinationDescription | 指定用于管理对象的信息。默认值：目标对象的说明

> ### 在客户机启动时覆盖属性值

> 像使用任何 Java 应用程序一样，您可以使用命令行来启动消息传送应用程序以指定系统属性。此机制也可以用来覆盖客户机应用程序代码中使用的受管理对象的属性值。例如，可以覆盖在客户机应用程序代码中通过 JNDI 查找来访问的受管理对象的配置。

> 要在客户机应用程序启动时覆盖受管理对象的设置，请使用以下命令行语法：

> java [[-Dattribute=value ]] clientAppName

> 其中，attribute 与“连接工厂受管理对象属性”中记录的任意 ConnectionFactory 受管理对象的属性相对应。

> 例如，如果希望客户机应用程序连接到其他代理，而不是连接到在客户机代码中访问的 ConnectionFactory 受管理对象中指定的代理，可以使用命令行覆盖来启动客户机应用程序以设置另一个代理的 imqBrokerHostName 和 imqBrokerHostPort。

> 如果已将受管理对象设置为只读，则无法使用命令行覆盖来更改其属性的值。所有此类覆盖将被忽略。

> 上一章 目录 索引 下一章

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