(來源:http://www.ccw.com.cn)
隨着計算機網絡和分佈式應用的不斷髮展,遠程消息傳遞越來越成爲應用系統中不可缺少的組成部分。商業消息中間件的出現保證了消息傳輸的可靠性,高效率和安全性,同時也減少了系統的開發週期。目前應用最多的消息中間件產品爲IBM MQSeries。本文就針對MQ的基本操作與配置進行詳細的闡述,希望對讀者有所幫助。 |
MQ中有幾個很重要的組件:隊列管理器(QueueManager)、隊列(Queue)和通道(Channel)。其基本的操作方法如下: |
如果隊列是默認隊列管理器中的隊列,可以不帶其隊列管理器的名字 |
如果隊列是默認隊列管理器中的隊列,可以不帶其隊列管理器的名字 |
runmqchl –c ChlName –m QmgrName |
runmqlsr –t TYPE –p PORT –m QMgrName |
DEFINE QLOCAL(QNAME) DEFPSIST(YES) REPLACE |
DEFINE QALIAS(QALIASNAME) TARGQ(QNAME) |
RNAME(AAA) RQMNAME(QMGRNAME) + |
DEFINE QMODEL(QNAME) DEFTYPE(TEMPDYN) |
DEFINE QLOCAL(QTNAME) USAGE(XMITQ) DEFPSIST(YES) + |
INITQ(SYSTEM.CHANNEL.INITQ)+ |
PROCESS(PROCESSNAME) REPLACE |
DEFINE PROCESS(PRONAME) + |
APPLICID(’ runmqchl -c SDR_TEST -m QM_ TEST’) |
其中APPLTYPE的值可以是:CICS、UNIX、WINDOWS、WINDOWSNT等 |
DEFINE CHANNEL(SDRNAME) CHLTYPE(SDR)+ |
CONNAME(‘100.100.100.215(1418)’) XMITQ(QTNAME) REPLACE |
其中CHLTYPE可以是:SDR、SVR、RCVR、RQSTR、CLNTCONN、SVRCONN、CLUSSDR和CLUSRCVR。 |
DEFINE CHANNEL(SDR_ TEST) CHLTYPE(RCVR) REPLACE |
DEFINE CHANNEL(SVRCONNNAME) CHLTYPE(SVRCONN) REPLACE |
DISPLAY QUEUE(QNAME) [ALL] |
DISPLAY QUEUE(QNAME) DESCR GET PUT |
DISPLAY QUEUE(QNAME)MAXDEPTH CURDEPTH |
ALTER QMGR DESCR(‘NEW DESCRIPTION’) |
ALTER QLOCAL(QNAME) PUT(DISABLED) |
ALTER QALIAS(QNAME) TARGQ(TARGQNAME) |
以上講述了MQ的基本命令操作,但只知道這些是沒有實際意義的。MQ的最終目的是實現遠程通信,所以下面就以一個具體的例子來說明如何實現遠程連接。這個例子的目的是建立可以實現消息傳遞的一對MQ服務器,它們分別基於NT和UNIX平臺。 |
DEFINE QL(NT.DEADQ) DEFPSIST(YES) REPLACE |
ALTER QMGR DEADQ(NT.DEADQ) |
APPLICID(’ runmqchl -c SDR_NT -m QM_NT’) |
DEFINE QL(QT_NT) USAGE(XMITQ) DEFPSIST(YES) + |
INITQ(SYSTEM.CHANNEL.INITQ)+ |
創建遠程隊列定義,對應於UNIX機器上的本地隊列Q_UNIX,傳輸隊列爲QT_NT |
RNAME(Q_UNIX) RQMNAME(QM_UNIX)+ |
創建發送方通道,其傳輸隊列爲QT_NT,遠程主機地址爲10.10.10.2,偵聽端口爲1414 |
DEFINE CHANNEL(SDR_NT) CHLTYPE(SDR)+ |
CONNAME(‘10.10.10.2(1414)’) XMITQ(QT_NT) REPLACE |
DEFINE CHANNEL(S_NT) CHLTYPE(SVRCONN) REPLACE |
MQSeries 1414/tcp #MQSeries channel listener |
修改/etc/inetd.conf文件,加入一行(啓動偵聽程序) |
MQSeries stream tcp nowait mqm /usr/lpp/mqm/bin/amqcrsta amqcrsta –m QM_UNIX |
DEFINE QL(UNIX.DEADQ) DEFPSIST(YES) REPLACE |
ALTER QMGR DEADQ(UNIX.DEADQ) |
DEFINE CHANNEL(SDR_NT) CHLTYPE(RCVR) REPLACE |
DEFINE QL(Q_UNIX) DEFPSIST(YES) REPLACE |
DEFINE CHANNEL(S_UNIX) CHLTYPE(SVRCONN) REPLACE |
經過以上操作之後,遠程連接的配置工作完成。接下來需要驗證配置是否正確。 |
runmqchl –c SDR_NT –m QM_NT 或 start chl(SDR_NT) |
/usr/mqm/samp/bin/amqsget Q_UNIX QM_UNIX |
另,在NT下一般情況下在建立隊列管理器時會自動建立偵聽器,啓動隊列管理器時則會自動啓動偵聽程序。當然也可以手動配置偵聽程序。 |
修改/winnt/system32/drivers/etc/services文件,在文件中加入一行: |
MQSeries 1414/tcp #MQSeries channel listener |
runmqlsr –t tcp –p 1414 –m QM_NT |
以上說明了怎樣建立簡單的單向傳輸網絡。消息從NT端傳送到UNIX端。建立從UNIX端到NT端的遠程連接和以上相仿,要建立雙向的傳輸網絡也是同樣的道理。 |
用JMS實現消息的發送和接收時,經常會用到JNDI。因爲JNDI這種方式比較靈活,對於編程也比較簡單。 |
在安裝了MQSeries Client for Java之後,在/java/bin目錄下找到JMSAdmin.config文件。該文件主要用來說明Context的存儲方式及存儲地址,對應於文件中的兩個參數INITIAL_CONTEXT_FACTORY和PROVIDER_URL。典型的JMSAdmin.config文件內容如下: |
#INITIAL_CONTEXT_FACTORY=com.sun.jndi.ldap.LdapCtxFactory |
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory |
#INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory |
#PROVIDER_URL=ldap://polaris/o=ibm,c=us |
PROVIDER_URL=file:/d:/temp |
#PROVIDER_URL=iiop://localhost/ |
SECURITY_AUTHENTICATION=none |
INITIAL_CONTEXT_FACTORY表示JMSAdmin Tool使用的服務提供商。當前有三種受支持的值。com.sun.jndi.ldap.LdapCtxFactory用於LDAP,如果使用它就必須安裝一個LDAP服務器。com.sun.jndi.fscontext.RefFSContextFactory用於文件系統上下文,它只需要使用者提供存放上下文的文件路徑。com.ibm.ejs.ns.jndi.CNInitialContextFactory是專門爲websphere提供的,它需要和websphere的CosNaming資源庫一起使用。 |
PROVIDER_URL表示會話初始上下文的URL,由JMSAdmin tool實現的所有JNDI操作的根。它和INITIAL_CONTEXT_FACTORY一一對應。 |
ldap://hostname/contextname 用於LDAP |
file:[drive:]/pathname 用於文件系統上下文 |
iiop://hostname[:port]/[?TargetContext=ctx] 用於訪問websphere CosNaming名稱空間 |
最後還有一個參數SECURITY_AUTHENTICATION,用於說明JNDI是否把安全性憑證傳遞給了您使用的服務供應商。只有當使用了LDAP服務供應商時,才使用此參數。此參數有三個值,none(匿名認證)、simple(簡單認證)和CRAM-MD5認證機制。如果沒有提供有效值,缺省值爲none。 |
確認配置文件之後,可以在/java/bin目錄下啓動JMSAdmin控制檯。也可以在任何目錄下用下面的命令來啓動控制檯: |
JMSAdmin –cfg MQ_JAVA_INSTALL_PATH/java/bin/JMSAdmin.config |
其中MQ_JAVA_INSTALL_PATH爲MQSeries Client for Java安裝的根目錄。 |
若啓動失敗,則好好檢查一下您的環境變量是否設置正確。根據我個人的經驗,除了把com.ibm.mq.jar和com.ibm.mqjms.jar加入到環境變量外,還要把fscontext.jar和providerutil.jar加入到環境變量。 |
進入JMSAdmin控制檯後,您可以自由定義sub context。對於子上下文的操作,主要有一下命令: |
當然,在這裏的主要任務並非是用來定義sub context,而是用來定義以下幾個對象: |
(還有其它的一些對象,如MQXAQueueConnectionFactory等,不常用到,在此不作說明。) |
可以使用很多動詞來操縱目錄名稱空間中的受管理對象。ALTER、DEFINE、DISPLAY、DELETE、COPY和MOVE,它們的用法都算比較簡單,這裏只列舉一二以作說明。 |
例一:定義一QueueConnectionFactory,連接主機10.10.10.18,端口1414 |
DESC(Example Queue Connection Factory)+ |
例二:定義一Queue,其對應於MQ中的Q_EXAMPLE |
上面我們說明了怎樣用JMSAdmin Tool定義MQ對象的上下文。我們的最終目的是要用JMS來實現MQ編程,以實現在程序中對MQ隊列進行收、發消息。所以,下面我們將重點討論一下MQ的JMS實現。 |
如果您對JMS編程很熟悉,那麼您也就會用JMS來實現MQ編程,因爲用JMS來編寫MQ程序與編寫一般的JMS程序沒有太大的差別。舉個例子,當我們想發送一條消息到MQ的隊列中,再從該隊列中取回消息時,我們編程時主要有四個步驟。首先我們要初始化在程序中要用到的對象,然後纔可以發送消息到隊列中去,再就是收取消息了,最後要清除那些永久對象。這些都和普通的JMS程序相當。程序的源代碼如下: |
import java.util.Hashtable; |
import javax.naming.directory.*; |
protected QueueConnectionFactory factory=null; |
protected QueueConnection connection; |
protected QueueSession queueSession; |
protected TextMessage outMessage; |
protected QueueSender queueSender; |
protected QueueReceiver queueReceiver; |
public static final String qcfLookup="EXAMPLEQCF"; |
public static final String qLookup="EXAMPLEQL"; |
public static final String icf = "com.sun.jndi.fscontext.RefFSContextFactory"; |
public String url ="file:/d:/temp"; |
public void sampleInit() throws Exception { |
Hashtable environment = new Hashtable(); |
environment.put(Context.INITIAL_CONTEXT_FACTORY, icf); |
environment.put(Context.PROVIDER_URL, url); |
environment.put(Context.REFERRAL, "throw"); |
Context ctx=new InitialDirContext(environment); |
factory = (QueueConnectionFactory)ctx.lookup(qcfLookup); |
q1=(Queue)ctx.lookup(qLookup); |
connection = factory.createQueueConnection(); |
queueSession = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); |
queueSender = queueSession.createSender(q1); |
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); |
outMessage = queueSession.createTextMessage(); |
queueReceiver = queueSession.createReceiver(q1); |
public void sendMessageOut(String message) throws JMSException { |
outMessage.setText(message); |
queueSender.send(outMessage); |
public String receiveMessage() throws Exception{ |
return ((TextMessage)queueReceiver.receive()).getText(); |
public void sampleClose() throws JMSException { |
public static void main(String[] args){ |
sample sp = new sample(); |
sp.sendMessageOut("Hello World!"); |
java.lang.Thread.sleep(4000); |
System.out.println("Receive text is : "+rec); |
MQ在WINDOWS平臺下具有圖形化管理界面,但在UNIX平臺下卻只能通過命令行來進行操作。這樣就給使用者帶來很大的不便。我們都希望能通過圖形界面來進行管理配置。爲了實現我們的想法,我們就必須建立遠程管理。 |
1.被管理隊列管理器上的命令隊列SYSTEM.ADMIN.COMMAND.QUEUE存在並可用。對於MQ 2版本應執行 amqscoma.tst 腳本來創建。 |
2.使用strmqcsv命令來啓動被管理隊列管理器上的命令服務器。 |
3.確定被管理隊列管理器上的服務器連接通道SYSTEM.ADMIN.SVRCONN是否存在,如果不存在則創建它。 |
4.一般Unix、Linux平臺中MQ默認的字符集爲819,而Windows平臺爲1381,所以你必須改變其字符集,使兩邊的字符集相同。一般改被管理的字符集。 |
5.如果被管理隊列管理器上的操作用戶與管理隊列管理器上的操作用戶不同,那麼你首先要確認管理隊列管理器上的操作用戶在被管理隊列管理器上存在並且有管理MQ的權限,再者,你需要修改服務器連接通道SYSTEM.ADMIN.SVRCONN的MCAUSER屬性爲管理隊列管理器上的操作用戶。 |
做完這些工作之後,直接在管理隊列管理器的MQ管理工具中顯示被管理隊列管理器即可。然後你就可以象操作本地隊列管理器一樣,在被管理隊列管理器上定義你需要的MQ對象。 |
在配置遠程連接的時候,我們曾經創建過進程定義。那我們爲什麼要去創建進程定義呢?這就涉及MQ通道維護的概念。 |
通道長時間沒有消息觸發就會自動斷開連接,不再保持運行狀態。時間的長短可以由自己設定,默認值爲6000秒。消息請求再次來臨的時候,就必須再次啓動通道。有些通道,如服務器連接通道、接收方通道等是自動觸發啓動的。當消息請求發送到通道後,通道立即啓動,進入運行狀態。但也有一些通道不會自動啓動,最典型的就是發送方通道。當有消息請求需要使用通道進行消息傳遞的時候,發送方通道也不會自動啓動並把消息發送到遠程隊列,而是把消息留在了與其相關聯的傳輸隊列中。 |
但是,在實際應用中我們又不可能每過一段時間去啓動一次通道,或當有消息來再去啓動通道。那應該怎麼辦?首先我們創建一個進程定義,這個進程定義的目的就是用來啓動發送方通道。然後我們在傳輸隊列的進程名稱屬性欄指定剛纔定義的進程定義名稱,再把觸發器控制開關打開。這樣,當有消息進入傳輸隊列後,傳輸隊列的觸發器會啓動觸發執行指定的進程,從而啓動發送方通道,把消息傳輸到遠程隊列中去。 |
也許你會說你已經理解了MQ,包括基本概念、配置、管理以及程序的編寫,那麼恭喜你。我也希望如此。不過MQ也許並非如此簡單,因本人水平有限,也只能到此爲止,希望大家再接再厲。順便說一句,如果有什麼好想法,千萬別忘了告訴我一聲。 |