发布/订阅是一种异步消息传输机制,它定义了应用程序模型,把消息的发布者(Publisher)与消息的订阅者(Subscriber)以一种松耦合的方式联系在一起,它们不需要知道对方的任何信息,甚至不需要知道对方是否存在,就可以实现消息的异步传递。发布者和订阅者之间通过主题(Topic)交换信息:发布者把信息发布到主题字符串(Topic String),订阅者在主题上注册并接收信息,通过这种方式主题字符串把发布者和订阅者连接起来。
下面介绍一个发布/订阅的具体实例。图 1 是 IBM Redbooks RSS 网站。网站(发布者)定期在每类技术专题(主题)发布最新的 Redbooks 信息,用户(订阅者)在自己感兴趣的技术专题订阅,当该技术专题有最新的 Redbooks 信息到达时,用户便会接收到。网站不需要知道哪些用户定订阅了哪些技术专题,它们需要做的只是在各类技术专题发布 Redbooks 信息。用户关心的只是 Redbooks 信息,它们不需要知道是谁发布的,它与网站之间是松耦合关系,这就构成了一个典型的发布/订阅系统。
主题(Topic)和订阅(Subscription)是发布/订阅中重要的对象,MQ V7 把它们作为新增加的对象并整合到队列管理器中。本文将从主题和订阅展开讲解,详细讲述它们在 MQ V7 中的定义和属性以及 MQ V7 是如何通过主题和订阅对发布/订阅进行管理。接下来本文将通过复杂的 MQ V7 发布/订阅环境讲解分布式发布/订阅技术,这部分内容是 MQ V7 发布/订阅技术中的高级部分,以使读者对 MQ V7 发布/订阅技术有更深入的了解。
MQ V7 把发布/订阅消息机制整合到队列管理器中,这样做很容易对发布/订阅进行管理、配置等操作。可以通过 MQSC 脚本在命令行管理配置主题和订阅,也可以通过 MQ Explorer 图形化的方式管理配置主题和订阅。
WebSphere MQ V7 把主题作为一种新的对象类型定义在队列管理器中。主题字符串是主题 对象的属性,它是连接发布者和订阅者之间的“纽带”。
在 MQ V7 队列管理器内部,主题是以主题树的继承形式展现的。图 2 是一棵主题树,在 主题树的最顶端是树的根节点 SYSTEM.BASE.TOPIC,其他的节点可以分成两类:一类是管理节点,一类是非管理节点。
管理节点:在主题树节点中,定义了主题对象的节点被称为是管理节点,它们是主题树中永久部分,不会因为队列管理器重启被系统删除掉。管理节点允许在其上定义该节点的属性,非管理节点可以继承该属性。图2 中 主题 FIFA 所在的节点是管理节点,因为在该节点上定义了主题对象 FOOTBALL 并定义了主题字符串 FIFA。
非管理节点:主题字符串并不用预先定义,应用程序在发布或订阅一个不存在的主题字符串时,该主题字符串会自动生成,它在主题树中以非管理节点存在,非管理节点的所有属都性继承在它以上的第一个管理节点的属性。在图 2 中主题字符串 FIFA/EURO 不是预先定义的,它在主题树中以非管理节点形式存在,它继承 FIFA 所在管理节点的所有属性。
对于管理节点,需要预先定义主题对象,在 MQ V7 中,可以通过 MQSC 或 MQ Explorer 定义主题对象。清单 1 中使用 MQSC 脚本命令定义一个主题,主题名字是 WEST, 主题字符串是 NBA/LAKER。
DEFINE TOPIC(WEST) TOPICSTR(NBA/LAKER) DESCR('This is a TOPIC') PUB(ASPARENT) SUB( ENABLED) + WILDCARD(PASSTHRU) 1 : DEFINE TOPIC (WEST) TOPICSTR(NBA/LAKER) DESCR('This is a TOPIC') PUB( ASPARENT) SUB(ENABLED) WILDCARD(PASSTHRU) AMQ8690: WebSphere MQ TOPIC created. |
清单 1 中参数的意义:
TOPIC:主题名字。
TOPIC STR:主题字符串。
DESCR:对主题的描述。
PUB:是否允许发布者在这个主题上发布消息,它有三个选项:ENABLED 允许,DISABLED 禁止,ASPARENT 继承父节点。在图 3 中,由于 WEST 所在的节点 PUB 属性是 ASPARENT,并且它的父节点不是管理节点,所以 WEST 所在的节点继承了根结点 SYSTEM.BASE.TOPIC 的属性。
SUB:是否允许订阅者在这个主题上订阅操作。它有三个选项:ENABLED 允许,DISABLED 禁止,ASPARENT 继承父节点。
WILDCARD:通配符。它有两个选项:PASSTHRU 和 BLOCK。举例说明它们的含义:在图 3 中,若一个订阅者订阅主题字符串“#”,这会导致在主题树中所有主题上的发布内容被发送到订阅者。如不希望在 FIFA 以下的节点接收到发布内容,可以按照清单 2 上的命令修改 WILDCARD 属性为 BLOCK。WILDCARD 的默认属性值为 PASSTHRU,没有 ASPARENT 属性。
图 3. 继承管理节点属性
清单 2. 修改 WILDCARD 属性为 BLOCK
ALTER TOPIC(FOOTBALL) WILDCARD(BLOCK) 4 : ALTER TOPIC(FOOTBALL) WILDCARD(BLOCK) AMQ8691: WebSphere MQ TOPIC changed. |
清单 3 显示已经定义的主题 FOOTBALL 的信息。
DISPLAY TOPIC(FOOTBALL) 5 : DISPLAY TOPIC(FOOTBALL) AMQ8633: Display TOPIC details. TOPIC(FOOTBALL) TYPE(LOCAL) TOPICSTR(FIFA) DESCR( ) CLUSTER( ) DURSUB(ASPARENT) PUB(ASPARENT) SUB(ASPARENT) DEFPSIST(ASPARENT) DEFPRTY(ASPARENT) DEFPRESP(ASPARENT) ALTDATE() ALTTIME(01.57.11) PMSGDLV(ASPARENT) NPMSGDLV(ASPARENT) PUBSCOPE(ASPARENT) SUBSCOPE(ASPARENT) PROXYSUB(FIRSTUSE) WILDCARD(BLOCK) MDURMDL( ) MNDURMDL( ) |
清单 4 使用 DISPLAY TOPIC(*) MQSC 命令显示队列管理器中所有主题的定义,并用Where 语句根据主题字符串的值等于 (EQ) FIFA 对主题过滤,得到符合特定属性值的主题。
DISPLAY TOPIC(*) WHERE(TOPICSTR EQ FIFA) 6 : DISPLAY TOPIC(*) WHERE(TOPICSTR EQ FIFA) AMQ8633: Display TOPIC details. TOPIC(FOOTBALL) TYPE(LOCAL) TOPICSTR(FIFA) |
清单 5 显示主题字符串 FIFA 所在节点的状态:DISPLAY TPSTATUS(Topic-String)。从返回值中可以看到主题字符串“FIFA”的主题名字是 FOOTBALL,这个节点是 ADMIN 及管理节点。
DIS TPSTATUS(FIFA) 11 : DIS TPSTATUS(FIFA) AMQ8754: Display Topic status details. TOPICSTR(FIFA) ADMIN(FOOTBALL) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) PMSGDLV(ALLDUR) NPMSGDLV(ALLAVAIL) RETAINED(NO) PUBCOUNT(0) SUBCOUNT(0) PUBSCOPE(ALL) SUBSCOPE(ALL) |
清单 6 使用 DISPLAY TPSTATUS(FIFA/+)返回 FOOTBALL 节点的下一级所有节点的状态,因为该节点是非管理节点,所以 ADMIN 参数是空。
DIS TPSTATUS(FIFA/+) 2 : DIS TPSTATUS(FIFA/+) AMQ8754: Display Topic status details. TOPICSTR(FIFA/EURO) ADMIN( ) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) PMSGDLV(ALLDUR) NPMSGDLV(ALLAVAIL) RETAINED(NO) PUBCOUNT(0) SUBCOUNT(1) PUBSCOPE(ALL) SUBSCOPE(ALL) |
清单 7 使用 DISPLAY TPSTATUS(FIFA/#) 命令不仅返回了 FOOTBALL 节点本身的状态,还返回了 FOOTBALL 以下所有节点的状态。
清单 7. 在 DISPLAY TPSTATUS 命令中使用“#”
DIS TPSTATUS('FIFA/#') 12 : DIS TPSTATUS('FIFA/#') AMQ8754: Display Topic status details. TOPICSTR(FIFA/EURO/ESP) ADMIN( ) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) AMQ8754: Display Topic status details. TOPICSTR(FIFA) ADMIN(FOOTBALL) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) PMSGDLV(ALLDUR) NPMSGDLV(ALLAVAIL) SUBSCOPE(ALL) AMQ8754: Display Topic status details. TOPICSTR(FIFA/EURO) ADMIN( ) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) PMSGDLV(ALLDUR) NPMSGDLV(ALLAVAIL) SUBSCOPE(ALL) |
值得注意的是,DISPLAY TPSTATUS 命令不支持“*”,但是可以在 WHERE 语句中使用“*”作为过滤条件。清单 8 中命令返回以 FIFA/EURO/E 开头节点的状态。
DISPLAY TPSTATUS('FIFA/#') WHERE(TOPICSTR LK FIFA/EURO/E*) ALL 1 : DISPLAY TPSTATUS('FIFA/#') WHERE(TOPICSTR LK FIFA/EURO/E*) ALL AMQ8754: Display Topic status details. TOPICSTR(FIFA/EURO/ESP) ADMIN( ) MDURMDL(SYSTEM.DURABLE.MODEL.QUEUE) MNDURMDL(SYSTEM.NDURABLE.MODEL.QUEUE) DEFPSIST(NO) DEFPRTY(0) DEFPRESP(SYNC) DURSUB(YES) PUB(ENABLED) SUB(ENABLED) PMSGDLV(ALLDUR) NPMSGDLV(ALLAVAIL) RETAINED(NO) PUBCOUNT(0) SUBCOUNT(0) PUBSCOPE(ALL) SUBSCOPE(ALL) |
另外,可以使用 DISPLAY TPSTATUS(‘#’) 返回主题树中所有节点的状态,也可以使用DISPLAY TPSTATUS(+) 返回主题树根结点的状态。
上面详细介绍了如何使用 MQSC 脚本命令实现对主题的管理,接下来我们将介绍如何使用 MQ Explorer 和 MQSC 脚本实现对订阅的管理。
WebSphere MQ V7 提供了两种管理订阅的方法,一种是通过 MQ Explorer 管理,另一种是通过 MQSC 命令管理。
打开 MQ V7 Explorer,展开队列管理器目录结构,找到被管理的队列管理器,右击“Subscriptions”,如图 4:
点击“Subscription”打开创建新的“Subscription”窗口,如图 5:
在图 5 中可以通过 Select 按钮选择已经存在的主题,也可以在 Topic Name 和 Topic String 处输入。参数 Destination Class 有两个值 Managed 和 Provided,如果选择 Managed,队列管理器提供动态队列作为 Destination。如果选择 Provided,用户需要输入 Destination 值,该值必须是已经存在的队列。
WebSphere MQ V7 引入了新的 MQSC 命令定义和管理订阅。清单 9 使用 DEFINE SUB 命令定义新的订阅 SUB1,指定 Q1 为 Destination。
DEFINE SUB(SUB1) TOPICSTR(NEWS/SPORTS) DEST(Q1) 6 : DEFINE SUB(SUB1) TOPICSTR(NEWS/SPORTS) DEST(Q1) AMQ8094: WebSphere MQ subscription created. |
定义 Managed 类型的订阅可以不用指定 DEST 参数,清单 10 定义了 Managed 类型的 订阅 SUB2。
DEFINE SUB(SUB2) TOPICSTR(NEWS/ENT) DESTCLAS(MANAGED) 1 : DEFINE SUB(SUB2) TOPICSTR(NEWS/ENT) DESTCLAS(MANAGED) AMQ8094: WebSphere MQ subscription created. |
清单 11 使用 DISPLAY SUB 命令显示订阅的定义。
DIS SUB(SUB2) 1 : DIS SUB(SUB2) AMQ8096: WebSphere MQ subscription inquired. SUBID(414D5120514D35202020202020202020E3DB4F4920145108) SUB(SUB2) TOPICSTR(NEWS/ENT) TOPICOBJ( ) DEST(SYSTEM.MANAGED.DURABLE.494FDBE307511420) DESTQMGR(QM5) PUBAPPID( ) SELECTOR( ) USERDATA( ) PUBACCT(16010515000000B218D7C0694A597186E61BE3F603000000000000000000000B) DESTCORL(414D5120514D35202020202020202020E3DB4F4920145108) DESTCLAS(MANAGED) DURABLE(YES) EXPIRY(UNLIMITED) PSPROP(MSGPROP) PUBPRTY(ASPUB) REQONLY(NO) SUBSCOPE(ALL) SUBLEVEL(1) SUBTYPE(ADMIN) VARUSER(ANY) WSCHEMA(TOPIC) SUBUSER(root) |
在以上的章节,我们为您讲述了 MQ V7 对主题和订阅这两个对象的管理。接下来,我们将为您介绍两种分布式发布/订阅结构以帮助您更好的理解 MQ V7 发布/订阅技术。
MQ V7 中存在两种分布式发布/订阅结构:层次结构发布/订阅 (Hierarchical Pub/Sub) 和集群结构发布/订阅 (Clustered Pub/Sub)。在分布式发布/订阅网络中,连接在不同队列管理器上的发布者和订阅者通过分布式发布/订阅相互通信,实现消息发送和接收。
层次结构发布/订阅 (Hierarchical Pub/Sub)
MQ V7 层次结构发布/订阅通过队列管理器“父亲”与“孩子”的关系实现,“父亲”与“孩子”之间通过双向通道相互连接,发布者发布的消息通过“父亲”队列管理器路由到“孩子”队列管理器,最终被订阅者接收。
通过以下的步骤配置层次结构发布/订阅结构:
- “父亲”队列管理器与“孩子”队列管理器之间需要建立双向通道,定义通道的传输队列的名字为远程队列管理器的名字。
- 修改“孩子”队列管理器 PARENT 属性,设置它的值为“父亲”队列管理器的名字:ALTER QMGR PARENT(<parent qmgr>) 。
- 使用 DISPLAY PUBSUB TYPE(<parent qmgr>) 显示在层次结构发布/订阅结构中“父亲”或“孩子”队列管理器的状态,确认是否创建成功。
值得注意的是:每个“孩子”队列管理器只能有一个“父亲”,使用 ALTER QMGR PARENT命令更改“孩子”队列管理器的“父亲”,一旦这个命令生效,“孩子”队列管理器就会与原来的“父亲”断开连接,并向新的“父亲”发出连接请求。如果要完成与新的“父亲”队列管理器的连接,还需要在“父亲”和“孩子”之间建立双向通道。使用 ALTER QMGR PARENT(‘ ’) 命令,可以把队列管理器从层次结构中断开。
下面通过实例讲解消息在层次结构队列管理器中的传递过程。根据上面的步骤 1-3 定义队列管理器的层次结构,其中包含三个队列管理器 HQM1,HQM2,HQM3。HQM1 是 HQM2 和 HQM3 的“父亲”,如图 6 :
在 HQM3 中定义主题 T1 ,主题字符串是 /T1。当有 Subscriber 在/T1 上订阅的时候,HQM3 会发送 Proxy Subscription (代理类型订阅) 到与其相连的队列管理器中,本例中代理类型订阅先被发送到 HQM1 中,用 MQSC命令查看 HQM1 中的代理类型订阅的定义:
DIS SUB(*) WHERE(TOPICSTR EQ '/T1') SUBTYPE(PROXY) ALL |
从该命令的返回可以看出:在 HQM1 中,代理类型订阅的 Destination 队列管理器是HQM3,Destination 是 SYSTEM.BROKER.DEFAULT.STREAM,这说明代理类型订阅从 HQM3 发送到 HQM1 的 SYSTEM.BROKER.DEFAULT.STREAM 中。
代理类型订阅会被 HQM1 发送到与其相连的 HQM2 中,在 HQM2 可以用同样的MQSC 命令查看代理类型订阅的定义:
DIS SUB(*) WHERE(TOPICSTR EQ '/T1') SUBTYPE(PROXY) ALL |
从该命令的返回可以看出:在 HQM2 中,代理类型订阅的 Destination 队列管理器是HQM1,Destination 仍是 SYSTEM.BROKER.DEFAULT.STREAM,这说明这个代理类型订阅已经被传送到 HQM2。
当发布者在 HQM2 上向 /T1 发布消息,消息会被在 HQM2 上的代理类型订阅放到它的 Destination 中,即 HQM1 的 SYSTEM.BROKER.DEFAULT.STREAM,这一过程是通过 HQM2 和 HQM1 之间的通道传输队列实现的。同理,在 HQM1 上消息会被取走放到 HQM3 的 SYSTEM.BROKER.DEFAULT.STREAM 中。最后,消息被连接到 HQM3 上的 Subscriber 消费掉。
从上面的实例可以看出,发布/订阅消息在层次结构中传递主要依靠于代理类型订阅,通道和传输队列。
MQ V7 集群结构发布/订阅使用集群的方式实现队列管理器之间连接,在集群队列管理器上定义集群类型主题,这样就创建了集群结构发布/订阅。与传统的集群类似,集群结构发布/订阅的队列管理器也是多对多关系。不同点在于,在传统的集群中,集群类型的对象必须在定义完之后才能使用,比如对集群队列进行 Put/Get 消息操作,这个集群队列必须预先定义。在集群结构发布/订阅中,集群主题会在第一次使用它的时候自动定义,在主题树中生成的节点是非管理节点。当订阅者在集群主题上注册后,代理类型订阅会被发送到集群结构发布/订阅中所有的队列管理器,这个过程会自动定义通道,所以集群结构发布/订阅更像是每个队列管理器都通过自动定义的通道与其他所有的队列管理器相连。
举例说明这个过程:定义集群 MSG,包含 QM1,QM2,QM3,QM4,其中 QM1 和 QM2 是存储库,在 QM1 上定义集群主题 SPORTS,主题字符串是 /GLOBAL/SPORTS。这样,这个集群 MSG 就形成了集群结构发布/订阅,如图 7,Subscriber在 QM3 上注册主题字符串 /Global/Sports,会在 QM3 中动态生成一个订阅,它是 API 类型。QM3 会向集群中其他的队列管理器发送代理类型订阅,清单 12在 QM4 上显示代理类型订阅的定义,可以看出代理类型订阅的名字是 SYSTEM.PROXY.QM3 MSG /GLOBAL/SPORTS,发送代理类型订阅队列管理器的名字是 QM3,集群的名字是 MSG ,主题字符串是 /GLOBAL/SPORTS。
图 7. 集群结构发布/订阅
清单 12. 显示代理类型订阅定义
D:/>runmqsc QM4 5724-H72 (C) Copyright IBM Corp. 1994, 2008. ALL RIGHTS RESERVED. Starting MQSC for queue manager QM4. dis sub(*) subtype(proxy) all 1 : dis sub(*) subtype(proxy) all AMQ8096: WebSphere MQ subscription inquired. SUBID(414D5120514D3320202020202020202033E2434920000EA1) SUB(SYSTEM.PROXY.QM3 MSG /GLOBAL/SPORTS) TOPICSTR(/GLOBAL/SPORTS) TOPICOBJ( ) DEST(SYSTEM.INTER.QMGR.PUBS) DESTQMGR(QM3) PUBAPPID( ) SELECTOR( ) USERDATA( ) PUBACCT(16010515000000B218D7C0694A597186E61BE3F003000000000000000000000B) DESTCORL(000000000000000000000000000000000000000000000000) DESTCLAS(PROVIDED) DURABLE(YES) EXPIRY(UNLIMITED) PSPROP(MSGPROP) PUBPRTY(ASPUB) REQONLY(NO) SUBSCOPE(ALL) SUBLEVEL(1) SUBTYPE(PROXY) VARUSER(FIXED) |
如果发布者在 QM4 上向 /GLOBAL/SPORTS 发布消息,消息会被代理类型订阅传送到 QM3 中的 SYSTEM.INTER.QMGR.PUBS 队列里,订阅者取出该数据并消费掉。同理,在 QM1 或 QM2 上向 /GLOBAL/SPORTS 发布消息,消息会以同样的方式传递到 QM3,然后被订阅者消费掉。
由此可见,集群结构发布/订阅中消息的传递方式主要是依靠集群队列管理器,这一点与层次结构有着明显的区别。
本文通过大量的实例详细介绍了 WebSphere MQ V7 新加的两个重要对象主题和订阅,并在此基础上介绍了两种分布式发布/订阅,以及消息在两种分布式发布/订阅网络中传递的方式和原理。
学习
- WebSphere MQ V6 信息中心:提供全面 WebSphere MQ V6 技术文档。
- WebSphere MQ V7 信息中心:提供最新的 WebSphere MQ V7 技术。
- WebSphere Message Broker 信息中心:了解更多 Message Broker 技术信息。
- 实现 SOA 连接的第一步:WebSphere MQ V7 新功能:本文主要向您讲述了 WebSphere MQ V7 中的新功能,其中包括对 Web 2.0 的支持,发布/订阅、MQI 编程接口、MQ 客户端等方面的增强,对 MQ JMS 标准的增强以及管理方面的提升等。
- WebSphere MQ 产品专题:提供了关于 WebSphere MQ 的最新文章、教程等技术资源。
- 小楼消息中间件专栏:聆听 IBM 专家娄丽军对消息中间件技术的独特理解。
- WebSphere MQ V7.0 特性与增强:WebSphere MQ 红皮书中更加详细的讲述了关于 MQ V7 的一些新特性及增强功能。
- WebSphere MQ 产品页面:向您提供了 WebSphere MQ 产品相关的最新信息。
- WebSphere MQ 最佳实践 Top 15:本文通过列举有关使用 WebSphere MQ 来实现消息队列的 15 个最佳实践,从而简化了设计、构建、运行和维护 WebSphere MQ 解决方案等问题,以便实现 WebSphere MQ 的全部好处。
获得产品和技术
- 马上下载 WebSphere MQ V7 试用版。
- 更多 WebSphere 试用版软件下载。