级别: 初级 Mark Taylor (marke_taylor@uk.ibm.com), WebSphere MQ Technical Strategy, IBM 赫斯利(Hursley),联合王国
2003 年 4 月 01 日 这个月,我们请 Mark Taylor 先生来回答在分布式(非 z/OS)平台上开发 WebSphere MQ(以前称为 MQSeries)应用程序或用 WebSphere MQ 运行系统等问题。WebSphere MQ 消息传递产品使应用程序能够在超过 35 种 IBM 和非 IBM 平台(其中包括 Linux 和 Windows 2000)之间交换信息。
© Copyright International Business Machines Corporation 2003.All rights reserved.
这个月,我们请
Mark Taylor先生来回答在分布式(非 z/OS)平台上开发 WebSphere MQ(以前称为 MQSeries)应用程序或用 WebSphere MQ 运行系统等问题。WebSphere MQ 消息传递产品使应用程序能够在超过 35 种 IBM 和非 IBM 平台(其中包括 Linux 和 Windows 2000)之间交换信息。Mark 是一位技术战略家,他负责定义添加到 WebSphere MQ 新版本的功能。关于更多信息,参见
WebSphereBusiness Integration 专区。
我们衷心感谢所有提出问题的 WebSphere 开发者。
问:我们如何在 MQseries 群集设置中为 MQSeries Java 客户机实现透明的故障转移?例如,如果一个队列管理器在执行放置(put)或获取(get)操作的过程中发生了故障,客户机应该能够切换到下一个可用的队列管理器并以对应用程序透明的方式继续工作。
(由 SR 提出)
答:“群集”这个词有不同的意思。WebSphere MQ(WMQ)群集是为帮助路由队列管理器之间的消息而设计的。应用程序仍然必须连接到群集内单个的、已知的队列管理器才可以传输消息。不存在从一个客户机连接到任何一个 WMQ 群集成员的概念。群集的另一个意思是它可以用来实现故障转移,使用诸如 HACMP 等技术来实现。这些允许队列管理器在机器之间透明地移动。这里没有足够的篇幅让我们深入讨论所有的可能性,但是这两种类型的群集可以非常成功地进行协作。
事务是按连接管理的,并且要求保证只传递一次。如果一个应用程序或队列管理器异常终止,那么任何活动的事务都将回退。这意味着任何客户机应用程序都需要能够处理 CONNECTION_BROKEN 返回码并决定如何继续下去。您不能指望在 PUT 或 GET 过程中丢失连接后仍然能够继续进行下去。而是必须明确地重新连接,然后决定您想重新运行哪项工作,同时知道先前的操作将被回滚。事务完整性对于保证可靠的传输至关重要,也是您不能立即把请求重新发往另一个队列管理器的原因所在。
所以现在的问题是您在什么地方重新连接?
如果您正在使用故障转移群集,那么发生故障的队列管理器就在新的机器上变为可用的,但用的仍是原来的 TCP/IP 地址。对重新启动的队列管理器重复您原先的连接请求,就可以重复任何已经从先前的连接回退的工作。
如果您真想连接到另一个队列管理器,那么用 C 语言编写的客户机应用程序可以在 MQCONN 期间使用通配符和外部客户机通道文件(AMQCLCHL.TAB)。这样将从符合您选择标准的表中选出第一个可用的队列管理器。然而,Java 和 JMS 类目前的版本还无法访问那个文件,因此它们必须编写一列备用的连接。您既可以用显式的方法来做(例如,在您的程序内设置每个队列管理器的 TCP/IP 地址,直到连接成功为止),又可以通过遍历 ConnectionFactory 详细信息中的条目来完成,这些条目是通过 JNDI 访问的。
问:MQ 是运行在 Unix 机上。我有一个使用MQ 的服务进行消息传递的 NT 应用程序。我想要开发一个简单的 MQ 监视(MQ Monitoring)工具,它将向我提供队列深度以及队列中的消息内容。这个监视工具需要集成在该 NT 应用程序中,这样用户才可以查看队列深度和队列中的消息。这个应用程序使用 ORACLE 并且是用 C 编程语言和 Java 编写的。我们可以有哪些选择?我们用不起第三方的工具。
(由德意志银行(Deutsche Bank)的 SR 提出)
答:有许多 API 和技术可以用来发现队列的深度。您也许想要直接使用 MQINQ 或发送 PCF 消息到命令服务器,这取决于您的应用环境。要读消息的内容而不破坏消息,就要求您使用带 MQGMO_BROWSE 标志的 MQGET。在该产品附带的样本应用程序代码以及 SupportPacs 二者中都展示了如何使用这些接口。请特别看一下 MS02 和 MS0B,因为它们将帮助构建 PCF 消息。您还可以从那里获得几个独立的监视程序。
问:您能否解释一下从一个 Websphere V5 JNDI 应用程序到一个 Websphere MQ JMS 队列的命名路径(naming path )?是否有这样一个不错的计划,在开发过程中在桌面上使用本地提供者队列,并拓展到企业名称空间以便进行部署?
(由 RW 提出)
答:每个 JMS 供应商好象都有不同方法来指定如何从一个应用程序进行连接,也有不同的方法来定义连接和正在使用的队列的属性。因为 JMS 的目标之一就是不依赖供应商,所以标准需要公共接口,应用程序可以使用这些公共接口,而不必考虑 JMS 的供应商。因此,JMS 供应商自动使用了在一个目录(该目录在运行时被访问)内存储信息的能力。关于更多信息,请参阅
Implementing vendor-independent JMS solutions。
使用 WMQ JMS 实现,队列连接工厂(Queue Connection Factory)定义应用程序如何连接到一个队列管理器。这个操作在整个 TCP/IP 网络中经常以客户机(Client)模式进行。连接好之后,您就可以使用 Queue 对象在那个队列管理器上打开一个队列。在 JNDI 空间中管理的队列名称和 WMQ 看到的队列名称相同。在 WMQ 中通过 runmqsc 命令创建队列并不能自动使该队列可用于 JMS 应用程序。您需要通过 JSMAdmin 程序把一个相同名称的 Queue 对象放在 JNDI 中。
WebSphere Application Server V5.0 包含某种有限的管理功能,这种功能与单个缺省队列管理器的
runmqsc 和 JMSAdmin 功能结合在一起被称为嵌入式消息传递(Embedded Messaging)提供者。定义的队列只在那个缺省的队列服务器中可用。如果您想让 JMSAdmin 工具有充分的灵活性,能连接不同的队列管理器,那么您必须在嵌入式(Embedded)版本的基础上安装一个完全许可的 WMQ V5.3 副本。
从 JMS 到 JNDI 的路径提供了一定级别的隔离和间接性,使得动态改变“真正”的队列管理器非常方便,或许是从一个开发系统变为生产系统。但是,我也推荐过在应用程序外配置所有对象的名称 - 包括到 JNDI 服务的链接 -(也许在运行时可以把它们作为属性来引用)。请记住:JNDI 链接很容易引用工作站上的本地文件或者企业目录服务器。改变外部配置的属性使得在环境之间进行移动变得无足轻重。如果您的组织已经为其他使用 WMQ 的应用程序定义了命名约定,那么您就可以把这些应用到 JMS 世界中。
问:我怎样知道在每一个平台上安装的 WMQ 是什么版本?
答:您可以使用操作系统特定的命令来列出您安装了哪些版本的产品。例如,AIX 上用
lslpp 命令、HP-UX 上用
swlist 命令、Solaris 上用
pkginfo 命令。还有一个
mqver 命令(目前尚未记录)可以在 V5.2 和 V5.3 产品中使用。这显示了产品的基本级别,比如 530。CMVC 级别包含产品的编译日期。对于 IBM 服务来说,知道这个日期很有用,因为它们可以把这个日期放在 CSD 号后面并定制已经生成的 efix。我们确实想对这个命令做一些增强,以便更清楚地显示 CSD 号。
问:什么时候我们能够在分布式平台上使用共享队列?
答:我非常不愿意用“永远不能”这个词来回答这个问题,但我想这种功能出现在除 z/OS 之外的平台上的可能性极小。共享的队列(可被多个队列管理器同时访问)依赖于相当专门的设备部件所提供的服务 - 耦合能力(Coupling Facility)。这是硬件与软件的结合,提供的功能不仅仅是在机器间进行简单的内存共享。例如,有专门的操作可以处理对列表结构的更新。这种系统目前尚不可用于其他平台。因为性能和恢复的问题,我们对一些技术(这些技术将允许不用专用的耦合能力对队列进行共享的更新)的研究很可能会失败。分布式两阶段事务在匹配用专门的队列管理器获得的服务时效率还不够高。目前,如果您需要共享队列提供的平行可伸缩性和恢复能力,那么 z/OS 正好能满足您的需要。
问:我的应用程序好象会丢失消息。为什么?
答:为避免丢掉消息(除非它被告知可以丢弃消息),WMQ 已经是非常谨慎了。一种明显的消息丢失情况的最常见原因是这个消息已被定义为非持久的。许多人可能会想您可以把队列变为持久的,但 DEFPSIST 属性只设置一个缺省值。持久性其实是消息的属性而不是队列的属性。一个应用程序可以选择设置一个显式值或者允许从队列属性中选用缺省值。当队列管理器重新启动时非持久消息会被废弃,当发生通道故障时非持久消息也会被废弃。当您认为自己已经丢失了一条消息时,请别忘了查看它是否已经被作为非持久消息发送了。
消息可能被“丢失”的第二个原因是队列管理器没有把消息放到期望的队列中。消息并没有永久地丢失,只是放错了地方!请看一下每个队列管理器(消息可能已经通过它路由出去了)上定义的死信队列(Dead Letter Queue(DLQ))。如果在发送消息时出了问题,那么它或许已经被发送到 DLQ 了。
出现丢失消息这种情况的最后一种常见原因就是在 MQGET(WAIT)操作过程中客户机应用程序异常终止了。在重新启动时,一个我们期望的消息已经从队列中除去了。为避免发生这种问题,请确保使用事务(MQGMO_SYNCPOINT)进行 MQGET 调用。当 SVRCONN 通道试图发送消息到客户机程序却失败时,消息会回滚到它的队列。
问:因为消息正在使用中,所以我不能从队列中除去它。请问我怎样知道谁正在使用它?并且我怎样能够使他们停止使用该消息?
答:请看一下 WMQ V5.3 中引入的 DISPLAY QSTATUS 命令。它显示所有打开了队列的进程,这些进程中有应用程序也有通道。通道程序把近期使用过的队列句柄放入高速缓存,或许在保存期间有的队列仍处于被使用的状态。虽然通道最终会释放句柄,但 DISPLAY QSTATUS 信息会显示通道名称,所以如果必要的话您也可以立即强行结束它。
问:一个现存的应用程序正在把消息放到一个队列中。我现在需要能够把那些消息的副本发送到另一个队列,但不改变应用程序。请问这一点能否做到?
答:只要您是在分布式平台上使用 WMQ V 5.3,就请看一下 API Exit 接口。它使您能够拦截应用程序进行的每次 MQI 调用。无论应用程序何时执行 MQPUT,您都有一个出口对同样的数据执行相应的 MQPUT,把它们放到第二个队列中。另一种变通方法就是改变应用程序使用的队列。如果它是使用 ALAIS 定义,这一点就很容易做到,或者让应用程序从外部配置文件(将是一个临时的保存队列)来读取它的输出队列。然后编写一个新应用程序,该应用程序检索消息并把该消息的一个副本放在原先的输出队列上,把第二个副本放在其他地方。当然您或许同样能够使用 WMQ 消息代理产品的其中之一作为一个十分灵活的中介体。
问:我如何控制用于 JMS 应用程序的授权的用户标识?
答:如果应用程序以本地绑定的模式连接到队列管理器,那么用户标识是与正运行的进程关联在一起。如果应用程序作为客户机跨网络连接到队列管理器,那么 SVRCONN 定义的 MCAUSER 属性控制哪一个用户标识拥有该连接。如果 MCAUSER 是空白的(缺省设置),那么大多数系统都是使 JMS 应用程序带 mqm 权限运行,除非客户机程序已经提供了它自己的用户标识。
对于非常旧的 C 客户机(例如在 Windows 95 上),是通过设置环境变量来提供客户机的用户标识。
对于当前的 C 客户机,是自动从运行的程序中获取用户标识并发送到服务器。
对于 Java 和 JMS 客户机,必须在程序内提供用户标识。既可以通过设置 Environment 类中的值来提供,也可以通过使用 JMS 版本的 createQueueConnection 方法来提供,该方法用用户标识和密码作为参数。如果没用这些方法中的任何一种来提供用户标识,那么就没有用户标识流过通道,将采用从 MCAUSER 得到的缺省值。
所有这三种机制的安全度相当(这种安全度非常低),因为客户机在所有情况下都只是声明一个用户标识。它们不保证用户能够在客户机上设置环境变量、创建新用户或者修改正执行的代码。
为确认客户机提供的身份,您必须使用通道安全出口,或者使用 SSL 认证。如果在 createQueueConnection 方法中使用密码,那么安全出口就可以使用该密码了。如果想看一对安全出口示例,请参阅 SupportPac IC72,这对出口是用 Java(用于编写客户机) 和 C (用于编写服务器)写的。
问:我能在整个因特网上使用 WMQ 吗?
答:大多数贯穿因特网的连接都应该会穿过一个或多个防火墙,配置这些防火墙是用来把机器隔离并提供安全性。虽然您可以通过打开通道所连接的端口号(缺省为 1414)直接穿过防火墙使用 WMQ,但管理员或许喜欢使用几个其他的工具。
如果您想限制发送方的本地端口号(通常不需要,但有时会有这样的请求),请使用通道的 LOCLADDR 属性。它允许启动通道(比如 SENDER 或者 CLNTCONN),说明出站 socket 来自于一个特定的 TCP/IP 地址并在一个已知的端口范围之内。
缺省情况下,WMQ 通道并不应用任何安全控制。一旦您开始跨因特网进行连接,就请看一下如何使用 V5.3 中提供的用于进行认证、加密和数据集成的 SSL 设备。
关于更灵活的方法,请参见 SupportPac MS81,WMQ internet pass-thru。它是一个完全受支持的软件包,可以在防火墙之间的 DMZ 中作为代理,转播 WMQ 通道协议流。它也可以用 HTTP 封装这些协议,使它更容易穿过防火墙。
关于作者  | |  | Mark Taylor has authored this article |
对本文的评价
|