使用 Websphere MQ 集群进行负载平衡

来源:互联网 发布:网站布局优化 编辑:程序博客网 时间:2024/05/19 14:00

http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1202_gaoly_mq/1202_gaoly_mq.html

MQ 集群概述

对于 MQ 两个队列管理器之间的通信,需要创建相应的对象。在发送队列管理器上,要创建一个远程队列,这个远程队列指向远程的目的地队列。还要创建一个传输队列做为存储转发队列以及一个发送通道指向接收队列管理器。在接收队列管理器上,要创建一个本地队列一个接收通道。如果一个网络中有多个队列管理器,并且两两之间要实现通信时,需要创建多个远程队列、传输队列和发送通道。

为了简化点对点通信的系统配置,通过 MQ 提供的群集功能,减少了集群中队列管理器上的 MQ 对象数量。群集内的两个队列管理器之间的通信,不需要两两间建立消息通道,而是使用群集通道与其它成员通信。只需要在每个队列管理器上创建两个集群通道。一个集群接收通道用来从集群中的其他队列管理器接收消息。一个集群发送通道用来发送消息。(其它的队列通道会自动建立)

集群的仓储库中含有集群的信息,如队列管理器的位置,通道等信息。仓储库分为完整仓储库队列管理器和部分仓储库队列管理器。完整仓储库队列管理器有集群中所有队列管理器的信息。而部分仓储库队列管理器中只有自身的和它要通信的队列管理器的信息。部分队列管理器通过与完整队列管理器通信,查询到相关的集群信息。

集群中共享的队列叫做集群队列。集群中的其他队列管理器可以向集群队列发送消息而不需要创建对应的远程队列定义。通常会在集群中创建多个同名的集群队列实例,分布在不同队列管理器上。当消息发送到集群队列时,MQ 会通过负载平衡算法,决定消息实际发送到哪里队列管理器的队列上。

创建 MQ 集群环境

清单 1. 创建队列管理器
 crtmqm -h 1024 -lp 20 -ls 5 -u FULL_QM1.DLQ FULL_QM1  strmqm FULL_QM1  runmqsc FULL_QM1  DEFINE LISTENER ('LISTENER.TCP') TRPTYPE (TCP) PORT (5000) CONTROL (QMGR)  START LISTENER ('LISTENER.TCP')  DEFINE CHANNEL ('SYSTEM.ADMIN.SVRCONN') CHLTYPE (SVRCONN)  END
在清单 1 中,创建了一个队列管理器 FULL_QM1。并且指定了这个队列管理器的监听端口为 5000。然后用同样的方法分别创建队列管理器 FULL_QM2,PART_QM1 和 PART_QM2,指定队列管理器的监听端口为 5001,5002 和 5003。
清单 2. 添加完整仓储库定义
 echo “ALTER QMGR REPOS ('NEW_CLUSTER')” | runmqsc FULL_QM1  echo “ALTER QMGR REPOS ('NEW_CLUSTER')” | runmqsc FULL_QM2
清单 3. 在队列管理器上创建接收通道
 echo “DEFINE CHANNEL ('TO.FULL_QM1') CHLTYPE (CLUSRCVR) TRPTYPE (TCP) CONNAME  ('127.0.0.1(5000)') CLUSTER ('NEW_CLUSTER')” | runmqsc FULL_QM1  echo “DEFINE CHANNEL ('TO.FULL_QM2') CHLTYPE (CLUSRCVR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5001)') CLUSTER ('NEW_CLUSTER')” | runmqsc FULL_QM2  echo “DEFINE CHANNEL ('TO.PART_QM1') CHLTYPE (CLUSRCVR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5002)') CLUSTER ('NEW_CLUSTER')” | runmqsc PART_QM1  echo “DEFINE CHANNEL ('TO.PART_QM2') CHLTYPE (CLUSRCVR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5003)') CLUSTER ('NEW_CLUSTER')” | runmqsc PART_QM2
每个队列管理器都需要一个接收通道指向自己。对于队列管理器 FULL_QM1,要指定连接名 CONNAME 中的 ip 地址和端口号为 FULL_QM1 自己的 ip 地址和监听端口号。对于其他的队列管理器也一样。在清单 3 中,创建了集群中四个队列管理器的接收通道。

清单 4. 在队列管理器上创建发送通道
 echo “DEFINE CHANNEL ('TO.FULL_QM2') CHLTYPE (CLUSSDR) TRPTYPE  (TCP) CONNAME ('127.0.0.1(5001)') CLUSTER ('NEW_CLUSTER')” | runmqsc FULL_QM1  echo “DEFINE CHANNEL ('TO.FULL_QM1') CHLTYPE (CLUSSDR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5000)') CLUSTER ('NEW_CLUSTER') ” | runmqsc FULL_QM2  echo “DEFINE CHANNEL ('TO.FULL_QM1') CHLTYPE (CLUSSDR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5000)') CLUSTER ('NEW_CLUSTER') ” | runmqsc PART_QM1  echo “DEFINE CHANNEL ('TO.FULL_QM2') CHLTYPE (CLUSSDR)  TRPTYPE (TCP) CONNAME ('127.0.0.1(5001)') CLUSTER ('NEW_CLUSTER') ” | runmqsc PART_QM2

在清单 4 中,定义了集群中四个队列管理器的发送通道。需要注意的是,对于两个完整仓储库队列管理器,需要建立相互间的发送通道。如对于完整仓储库队列管理器 FULL_QM1,需要建立到 FULL_QM2 的发送通道,发送通道的名字要和 FULL_QM2 的接收通道名字相同。并且要指定连接名 CONNAME 中的 ip 地址和端口号为 FULL_QM2 的 ip 地址和端口号。

而对于部分仓储库队列管理器,需要建立与某个或多个完整仓储库队列管理器的发送通道。对于 PART_QM1,这里建立了到完整仓储库队列管理器 FULL_QM1 的发送通道,并且发送通道的名字要和 FULL_QM1 的接收通道名字相同。连接名 CONNAME 也要指定为 FULL_QM1 的 ip 地址和端口号。另外,不需要定义 PART_QM1 指向另一个部分仓储库队列管理器 PART_QM2 的发送通道。

清单 5. 在两个部分仓储库队列管理器上定义集群队列
 echo “DEFINE QLOCAL ('TEST_QUEUE') CLUSTER ('NEW_CLUSTER')” | runmqsc PART_QM1  echo “DEFINE QLOCAL ('TEST_QUEUE') CLUSTER ('NEW_CLUSTER')” | runmqsc PART_QM2
集群的负载均衡是通过在集群内的不同队列管理器上建立同名的队列,即创建同一个队列的多个实例来实现的。每个队列实例都可以作为消息的目的地,MQ 使用负载平衡算法决定消息实际发送到哪个队列管理器。清单 5 中,在两个部分仓储库队列管理器上分别定义了一个集群队列 TEST_QUEUE,并且指定其 Cluster 属性值为 NEW_CLUSTER,这样这两个同名队列就可以在集群中共享了
图 1. 显示创建的集群 NEW_CLUSTER 的拓扑图

图 1. 显示创建的集群 NEW_CLUSTER 的拓扑图
图 1 是当前显示创建的集群 NEW_CLUSTER 的拓扑图。对于 PART_QM1,我们只是显示创建了 PART_QM1 到 FULL_QM1 的发送通道,之后集群会自动创建 PART_QM1 到 FULL_QM2 的发送通道。同样集群也会自动创建 PART_QM2 到 FULL_QM1 的发送通道。最后形成的集群拓扑图如图 2 所示。
图 2. 集群 NEW_CLUSTER 的拓扑图
图 2. 集群 NEW_CLUSTER 的拓扑图

使用集群队列时需要注意的几点:

如果对消息的逻辑处理有要求,或者对消息的处理顺序有要求,这时需要使用 MQOO_BIND_ON_OPEN 选项。例如,程序 A 向某个集群队列发送两条相互关联的消息,一条消息包含元数据,另一条消息包含实际数据内容,它们之间通过 groupId 相互联系。并且该集群队列在集群的两个队列管理器上各有一个同名集群队列实例。现在程序 B 需要从集群队列中取出相互关联的两条消息进行处理,如果这两条消息分别被发送到了两个不同的集群队列实例中,则程序 B 打开一个集群队列实例后,无法通过其中一条消息的 groupId,在同一个集群队列实例中找到另一条消息。要解决这个问题,可以将相互关联的消息发送到同一个集群队列实例上。在程序 A 将消息放入集群队列时,需要指定 MQOO_BIND_ON_OPEN 选项。

集群只在消息进入时实现负载平衡,一旦消息进入某个队列管理器上的集群队列,它就只能由该队列管理器处理。如果在消息被处理完之前,该队列管理器被挂起或者发生故障,已经进入该集群队列的消息将不能被处理。即其他队列管理器无法处理该队列管理器上同名的集群队列实例。这一点和 z/OS 的共享队列不同。在 z/OS 平台上,如果使用共享队列,多个队列管理器使用的是同一个队列实例,即使某个队列管理器不工作,其他的队列管理器可以处理该共享队列上的消息。


总结:
1、一个集群cluster中可以共享队列queue,负载均衡通过一个同名队列的多个实例实现。
2、在集群中,无论一个队列管理器要连接多少个远程队列管理器,最少只要创建一个集群发送通道和一个集群接收通道
3、LocalQ为本地队列,只有本地队列保存存放消息msg(接收请求
4、RemoteQ为远程队列,远程队列类似于其它管理器队列中的本地队列映射,不实际存留msg【影子队列】(发送请求),通过remoteQ将消息发送出去
5、 对于影子队列,只能put发送msg,不能get接收msg,接收只能去localQ上获取。即remoteQ只是代理没有缓存。

总之,队列管理器——发送通道——接收通道——队列,必不可少。
  
MQ出问题解决办法:
1、查看某一个queue的curdept属性,看是否有消息没处理  dis 队列名称
2、查看说有的channel  dis chl(*)


常用命令:
显示队列管理器: dspmq
运行队列管理器 eg:runmqsc  MQCHNRTIS01
显示队列管理器中的队列:dis q(*)
显示队列管理器中的通道: dis chl(*)
显示队列管理器中的通道的状态: dis chs(*)
退出队列管理器: end


0 0
原创粉丝点击