使用 Websphere MQ 集羣進行負載平衡

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章