客户端应用程序使用连接工厂受管理对象来创建与代理交换消息时使用的连接。连接工厂的属性定义了它所创建的所有连接的属性。创建连接后,将无法更改其属性;因此,配置连接属性的唯一方法就是设置用于创建连接的连接工厂的属性。
Message Queue 定义了两类连接工厂对象:
这两类对象共享相同的配置属性,可以通过这些属性来优化资源、性能和消息吞吐量。第 16 章,受管理对象属性参考详细列出并说明了这些属性,以下各节将对这些属性进行讨论:
连接处理属性指定了要连接到的代理地址,以及如何检测连接故障并尝试重新连接(如果要求)。表 16–1 概要介绍了这些属性。
最重要的连接处理属性是 imqAddressList ,该属性指定了要与之建立连接的一个或多个代理。该属性的值是一个字符串,它包含一个代理地址或者以逗号分隔的多个地址(如果是代理群集)。根据要使用的连接服务(请参见连接服务)和建立连接的方法,代理地址可以使用各种寻址方案:
mq,该方案使用代理的端口映射器为 jms 或 ssljms 连接服务动态指定端口。
mqtcp,该方案通过使用 jms 连接服务绕过端口映射器,而直接连接到指定端口。
mqssl,该方案通过使用 ssljms 连接服务与指定端口建立安全套接字层 (Secure Socket Layer, SSL) 连接。
http,该方案通过使用 httpjms 连接服务与指定 URL 处的 Message Queue 隧道 Servlet 建立超文本传输协议 (Hypertext Transport Protocol, HTTP) 连接。
https,该方案通过使用 httpsjms 连接服务与指定 URL 处的 Message Queue 隧道 Servlet 建立安全超文本传输协议 (Secure Hypertext Transport Protocol, HTTPS) 连接。
表 16–2 概述了这些寻址方案。
每个代理地址的通用格式为:
scheme://address
其中 scheme 是上面列出的寻址方案之一,而 address 表示代理地址本身。用于指定地址的准确语法因寻址方案而异,如表 16–2 中的最后一列所示。表 16–3 提供了各种地址格式的示例。
在多代理群集环境中,地址列表可能包含多个代理地址。如果第一次连接尝试失败,Message Queue 客户端运行时环境将尝试连接到列表中的另一个地址,依此类推,直到尝试完列表中的所有地址为止。其他两个连接工厂属性控制上述操作的执行方式:
imqAddressListBehavior 指定了尝试连接指定地址的顺序。如果将此属性设置为字符串 PRIORITY,将按地址在地址列表中的显示顺序尝试连接。如果属性值为 RANDOM,将按随机顺序尝试连接地址;这种方式非常有用,例如,当许多 Message Queue 客户端共享同一个连接工厂对象时,这种方式有助于防止所有客户端尝试连接到同一个代理地址。
imqAddressListIterations 指定了循环访问列表的次数,超过该次数后,将放弃尝试并报告故障。值为 -1 表示不限制重复次数:客户端运行时环境将一直尝试下去,直到成功建立连接或到达结束时间为止(以最先出现的情况为准)。
通过将连接工厂的 imqReconnectEnabled 属性设置为 true,可以使客户端在连接失败时自动重新连接到代理。imqReconnectAttempts 属性控制尝试重新连接到给定代理地址的次数;imqReconnectInterval 指定了两次尝试之间等待的时间间隔(以毫秒为单位)。
在代理地址列表 (imqAddressList ) 指定了多个地址的代理群集中,不但可以在原始代理上恢复失败的连接,而且还可以在群集中的其他代理上恢复失败的连接。如果重新连接到原始代理失败,则客户端运行时环境将尝试连接列表中的其他地址。imqAddressListBehavior 和 imqAddressListIterations 属性控制尝试连接地址的顺序和循环访问列表的次数,如前面一节所述。将以 imqReconnectInterval 的值(毫秒)作为时间间隔反复尝试连接每个地址,直到达到 imqReconnectAttempts 指定的最大尝试次数为止。
自动重新连接支持消息使用的所有客户端确认模式。重新建立连接之后,代理将重新传送以前传送过的所有未确认消息,并使用重新传送标志对其进行标记。应用程序代码可以使用此标志确定消息是否已使用但尚未得到确认。(但是,对于非长期订户,代理在关闭连接后不会保留消息。因此,在关闭连接时为这些订户生成的所有消息都将丢失,而不能在重新连接后进行传送。)在自动重新连接过程中将禁止生成消息;消息生成方无法向代理发送消息,直到重新建立连接为止。
自动重新连接提供连接故障转移,但不提供数据故障转移:客户端重新连接到其他代理实例时,因出现故障或断开连接的代理而保存的持久性消息和其他状态信息会丢失。尝试重新建立连接时,Message Queue 会维护客户端运行时环境提供的对象(如会话、消息使用方和消息生成方)。当连接失败时,系统也会维护临时目的地一段时间,因为客户端可能会重新连接并再次访问它们;在客户端重新连接并使用这些目的地之后,代理将会删除它们。如果重新连接时无法在代理上完全恢复客户端状态(例如,在使用事务会话时,客户端状态只在连接期间存在),将不会进行自动重新连接,而是调用该连接的异常处理程序。然后由应用程序代码捕获异常、重新连接并恢复状态。
可以将 Message Queue 客户端运行时环境配置成定期测试或 "ping" 连接,从而可以尽早检测出连接故障,以免在尝试传输消息时失败。对于只使用消息而不生成消息的客户端应用程序而言,这种测试尤为重要,因为如果不进行测试,这些应用程序将无法检测到连接失败。只是偶尔生成消息的客户端也可以利用此功能。
连接工厂属性 imqPingInterval 指定了 ping 连接的频率(以秒为单位)。默认情况下将此时间间隔设置为 30 秒;如果值为 -1,则表示禁用 ping 操作。
对失败的 ping 操作的响应因操作系统平台而异。在某些操作系统上,会立即向客户端应用程序的异常侦听器抛出异常。(如果客户端没有异常侦听器,则当它下次尝试使用连接时将会失败。)其他系统可能会继续尝试与代理建立连接,并缓冲后续的 ping 操作,直到某次尝试成功或缓冲区溢出为止。
表 16–4 中列出的连接工厂属性支持长期订户的客户端验证和客户端标识符设置。
必须对所有的代理连接尝试进行验证,方法是将用户名和密码与消息服务维护的用户系统信息库进行对照。连接工厂属性 imqDefaultUsername 和 imqDefaultPassword 指定了创建连接时使用的默认用户名和密码(如果客户端未明确提供它们)。
对于不希望在应用程序开发和测试期间填充用户系统信息库的开发者,为方便起见,Message Queue 提供了用户名和密码均为 guest 的 guest 用户帐户。这也是 imqDefaultUsername 和 imqDefaultPassword 属性的默认值,这样,如果未明确指定这些属性,客户端可以始终使用 guest 帐户获取连接。在生产环境中,只有在用户系统信息库中明确注册的用户,才应该访问代理连接。
根据 Java 消息服务规范的要求,当代理必须为客户端维护持久性状态时,连接必须提供一个唯一的客户端标识符。Message Queue 使用这些客户端标识符来跟踪主题目的地的长期订户。如果长期订户变为非活动状态,则代理会保留与该主题有关的所有传入消息,并在订户再次处于活动状态时传送这些消息。代理通过客户端标识符来标识订户。
客户端应用程序可以使用连接对象的 setClientID 方法以编程方式设置其自身的客户端标识符,这使得很难协调客户端标识符,从而不能确保每个标识符都是唯一的。通常,为客户端创建连接时,最好让 Message Queue 自动指定一个唯一的标识符。具体方法是,将连接工厂的 imqConfiguredClientID 属性设置为具有以下格式的值:
${u}factoryID
字符 ${u} 必须是该属性值的前四个字符。(如果大括号之间是 u 以外的任何字符,都会在创建连接时抛出异常;在任何其他位置,这些字符都没有特殊含义,将被视为纯文本。)factoryID 的值是唯一与此连接工厂对象关联的字符串。
为特定客户端创建连接时,Message Queue 通过将字符 ${u} 替换为 u:userName 来构建客户端标识符,其中 userName 是通过连接验证的用户名。这可以确保给定连接工厂创建的每个连接都有其自身的唯一客户端标识符,即使它们在其他所有方面都完全相同。例如,如果用户名为 Calvin,为连接工厂的 imqConfiguredClientID 属性指定的字符串为 ${u}Hobbes ,则指定的客户端标识符将为 u:CalvinHobbes。
如果两个客户端都尝试使用默认用户名 guest 获取连接,则此方案将不起作用,因为这两个客户端的客户端标识符具有相同的组成部分 ${u}。在这种情况下,只有请求连接的第一个客户端才能获取连接;第二个客户端的连接尝试将会失败,因为 Message Queue 不能创建两个具有相同客户端标识符的连接。
即使通过 imqConfiguredClientID 指定客户端标识符,客户端应用程序也可以使用连接方法 setClientID 来覆盖此设置。为了防止出现这种情况,可以将连接工厂的 imqDisableSetClientID 属性设置为 true。请注意,对于使用长期订户的应用程序,必须使用以下两种方法之一设置客户端标识符:使用 imqConfiguredClientID 以管理方式设置,或者使用 setClientID 以编程方式设置。
由于客户端发送和接收的“有效负荷”消息和 Message Queue 自身使用的控制消息(如代理确认消息)通过同一个客户端/代理连接进行传递,因此有效负荷流量过多将会干扰控制消息的传送。为了帮助缓解这个问题,可以使用表 16–5 中列出的连接工厂属性来管理两种消息的相对流量。这些属性分为以下四个类别:
确认超时指定等待代理确认的最长时间 (imqAckTimeout),超出此时间后将会抛出异常。
连接流计量通过将有效负荷消息拆分成具有指定大小 (imqConnectionFlowCount) 的若干批消息来限制有效负荷消息的传输,从而确保可以定期传送任何堆积的控制消息。
连接流控制限制有效负荷消息的数量 (imqConnectionFlowLimit),这些消息可以在连接上保持待处理状态,以等待使用。达到限制之后,将会暂停向连接传送有效负荷消息,直到等待使用的消息数低于该限制为止。此功能的使用受布尔标志 (imqConnectionFlowLimitEnabled) 控制。
使用方流控制限制有效负荷消息的数量 (imqConsumerFlowLimit),这些消息可以针对任何单个使用方保持待处理状态,以等待使用。 (也可以将此限制指定为特定队列目的地的属性 consumerFlowLimit。)达到该限制时,将会暂停向使用方传送有效负荷消息,直到等待使用的消息数(以 imqConsumerFlowLimit 的百分比表示)低于 imqConsumerFlowThreshold 属性指定的限制为止。这有助于防止同一连接上的任一使用方抢占其他使用方的流量,从而改善多个使用方之间的负载平衡。
使用上述流控制技术中的任何一种都需要在可靠性和吞吐量之间进行权衡;有关详细论述,请参见客户端运行时环境消息流调整。
表 16–6 列出了影响客户端队列浏览和服务器会话的连接工厂属性。imqQueueBrowserMaxMessagesPerRetrieve 属性指定了浏览队列目的地的内容时一次可以检索的最大消息数;imqQueueBrowserRetrieveTimeout 指定了等待检索消息的最长时间。(注意 imqQueueBrowserMaxMessagesPerRetrieve 不影响浏览消息的总数,只影响它们向客户端运行时环境传送时的分块方法:分成数量少但较大的块还是数量多但较小的块。客户端应用程序将总是接收队列中的所有消息。更改该属性的值可能会影响性能,但不会影响检索的数据总量。)布尔属性 imqLoadMaxToServerSession 管理应用服务器会话中连接使用方的行为:如果此属性的值是 true,客户端将向服务器会话中装入多个消息(消息数量不超过最大消息数);如果此属性的值是 false,则客户端一次只装入一条消息。
Java 消息服务规范定义了某些标准消息属性,JMS 提供者(如 Message Queue)可以选择是否支持这些属性。根据惯例,所有这些标准属性的名称均以字母 JMSX 开头。表 16–7 中列出的连接工厂属性控制 Message Queue 客户端运行时环境是否设置这些标准属性中的某些属性。对于生成的消息而言,这些属性包括:
JMSXUserID 发送消息的用户的标识
JMSXAppID 发送消息的应用程序的标识
JMSXProducerTXID 生成消息时所在的事务的事务标识符
对于使用的消息而言,这些属性包括:
JMSXConsumerTXID 使用消息时所在的事务的事务标识符
JMSXRcvTimestamp 消息传送到使用方的时间
对于某些 JMS 消息头字段,可以使用表 16–8 中列出的连接工厂属性来覆盖客户端设置的值。指定的设置将用于从该连接工厂获取的连接所生成的全部消息。可以采用这种方式覆盖的头字段包括:
上述每个字段都有两个属性:一个是布尔属性,用于控制是否可以覆盖字段,另一个用于指定字段的值。例如,用于设置优先级的属性是 imqOverrideJMSPriority 和 imqJMSPriority。此外还有一个属性 imqOverrideJMSHeadersToTemporaryDestinations,该属性控制覆盖值是否适用于临时目的地。
由于覆盖消息头可能会影响特定应用程序的需求,因此只有在咨询了应用程序的设计者或用户之后才应使用这些属性。