websphere mq 6.0 的介绍

来源:互联网 发布:信贷员客户资源软件 编辑:程序博客网 时间:2024/04/20 00:43
 WebSphere MQ(以下简称MQ)是IBM公司享有盛誉的商业通信中间件。它被世界范围的许多大型企业广泛采用。它提供一个具有工业标准、安全、可靠的消息传输系统。MQ基本由一个消息传输系统和一个应用程序接口组成。应用程序使用MQAPI(消息队列接口MQI)函数和队列管理器(MQ运行时刻的程序)进行通信。队列管理器在工作时,它需要用到对象如队列和通道。同时,队列管理器也是一个对象。图1所示为MQ应用程序在运行时刻的图示。


1 运行时刻的MQ1

  消息是一个信息单元,它由两部分组成:从一个程序发往另外一个程序的应用程序数据以及消息描述符或者消息头。
  消息描述符用来标识消息(message ID),同时它还包括一些控制信息,如消息类型,消息过期的时间,消息优先级等等。
  一条消息的最大长度为100MB,默认的最大消息长度为4MB。消息的最大长度依赖于MQ的版本。MQ第五版支持消息的最大长度为100MB
  队列是一个安全的存储消息的地方,消息的存储一般是有顺序的。因为消息存放在队列中,所以应用程序可以以不同的速度、在不同的时间、不同的地点相互独立的运行。
  消息队列通信是应用程序之间进行通信的一种方式。应用程序在没有专有连接或者物理连接的情况下,能够通过向队列写入或读出消息进行通信,也即程序之间不是通过互相调用,而是通过向队列发送数据来进行通信。在这种通信方式下,应用程序不需要具有并发性。对于异步的消息通信,程序发送方不需要专门等待已发消息的回复,而是可以处理下一个事件。与之相对的是,同步消息通信在处理下一个事件之前必须等待已发消息的回复。对于用户来说,底层的协议是透明的。用户只需要考虑会话的程序或数据入口。
MQ
应用于客户机/服务器模式或者分布式系统。应用程序可以工作在一个工作站上,也可以运行在不同平台的不同机器上。应用程序具有很好的移植性,能够轻松的从一个系统或者平台转移到另一个系统或者平台。程序的编写支持多种语言,包括Java。同样的,队列也适合许多不同的平台。
  因为MQ通过队列进行通信,所以它可以被看成是使用间接的程序--程序方式通信。程序员可以不指定接收消息的目标程序的名称,但是可以指定接收消息的队列的名称,每一个队列和一个程序相联系,一个程序可以有一个或者多个接收队列,而且可以有多个输出队列。输出队列包含着很多信息,这些信息可以是用来供服务器处理的,也可以是返还给发送消息的客户端的回复信息。
  使用MQ进行通信时不必担心目标程序是否可用或是否繁忙,甚至不用考虑目标机器是否正常运行或者是否连接上了。程序员发送消息给目标队列,而目标队列是和目标程序相联系的,目标程序可能目前不可用。不用担心,MQ能够解决这种情况,如果需要,它甚至能够启动目标程序。
  如果目标程序不可用,消息会停留在队列中,稍后再被处理。队列可以在发送消息的机器中,也可以在接收消息的机器中,这取决于两台机器的两个系统之间是否能够建立连接。应用程序可以整天运行,也可以采用激发机制,所谓激发,就是指当有一条或数条消息到达队列时自动启动某个程序。


2 消息和队列1

  图2说明了两个应用程序AB之间是如何进行通信的。可以看到有两个队列,各队列里面存放着要接收或者发送的消息。
  程序和队列之间的方形图表示MQI(消息队列接口API)。程序就是使用MQI来和MQ的实时程序--队列管理器进行通信的。
  简单地说:MQ的核心部分是一个能够存储消息的服务器及一组能够转发消息的进程,分布在多个系统(异地、异种平台)上的应用程序依靠这种机制来交换要处理的数据2。队列管理器作为一个服务器,把消息以可靠的方式存储,即使机器发生故障重新启动后依然不会丢失,其可靠级别与数据库服务器相等。队列管理器间通过特别的交换机制保证数据不会因为底层网络的故障而丢失,并且能够在多点间接力式地传送。
  JMSJ2EE中的一个接口标准,为JAVA程序定义了一种标准的使用消息交换数据的编程方式,但JMS本身并不能实现消息的传送,一个调用JMS的应用程序发出消息调用后,具体的消息传送工作还需要底层的消息中间件来执行传送工作。JMS的作用就是使应用程序开发人员不需要关心底层的传送软件的种类,同一段程序,既可以用MQ传送,也可以用其他消息中间件来传送,如WEBLOGIC内含的具有消息中间件功能的部件。
MQ
软件提供一个JAVA软件包,里面有JMS类库,和一套MQ的类库。不熟悉MQI编程方法的程序员可以用JMS,比较熟悉MQI编程方法的程序则可以用MQ类库来编程。下面的小程序是使用Java实现从队列管理器QM_SERVER中的队列INITQ写入或读出消息。

package transfer;
import com.ibm.mq.*;
public class SendMSG1
{
 private MQQueueManager qMgr;//定义一个队列管理器变量
 public static void main(String args[])
 {
  new SendMSG1();
 }
 public SendMSG1()
 {
  MQEnvironment.hostname="192.168.1.18";//本地IP
  MQEnvironment.channel="CHANNEL1";//用来通信的通道
  MQEnvironment.CCSID =1381;
  try{
   qMgr=new MQQueueManager("QM_SERVER");//队列管理器名称
   int openOptions=MQC.MQOO_INPUT_AS_Q_DEF|MQC.MQOO_OUTPUT

|MQC.MQOO_INQUIRE;
   MQQueue queue=qMgr.accessQueue("INITQ",openOptions,null,null,null);
   //建立连接
   MQMessage hello=new MQMessage();//要写入队列的消息
   try{
    hello.format=MQC.MQFMT_STRING ;
    hello.characterSet=1381 ;
    hello.writeString("这是测试!");
   }
   catch(java.io.IOException ex)
   {}finally{};
   MQPutMessageOptions pmo=new MQPutMessageOptions();
   for (int i=1;i<=5;i++)//将消息依次写入队列
   {
    hello.expiry=-1; //设置消息用不过期
    queue.put(hello);//将消息放入队列
   }
   queue.close() ;//关闭队列
   qMgr.disconnect() ; //断开连接
  }
  catch(Exception ex)
  {}
  finally{};
 }
}


  程序的运行结果如下图3所示:


3 程序运行结果界面

1.  这个例子仅仅是向队列INITQ写入了5条相同的消息,当然,在实际应用中,消息可能是多种多样的,如果要传送数据库的内容,则可以在写入消息时,用一些特殊的符号来将各字段的数据区分开,那么在消息读出时,也可以根据此特殊的符号来读取数据。依据同样的步骤:和队列管理器建立连接-从队列读取消息---关闭队列---断开连接,可以用Java写出如何从队列中读出消息。
  MQ有许多显著的优点,比如借住在不同的平台上使用相同的应用程序接口,它能轻松的实现跨平台通信,从而能够使开发人员避开网络的复杂性;比如它对消息的处理不依赖于时间,在消息创建和发送时,不受时间的限制,增加了处理的灵活性......

 二.
Websphere mq 的基本操作

一.MQ基本操作

MQ
中有几个很重要的组件:队列管理器(QueueManager)、队列(Queue)和通道(Channel)。其基本的操作方法如下:

创建队列管理器
crtmqm –q QMgrName
-q
是指创建缺省的队列管理器

删除队列管理器
dltmqm QmgrName

启动队列管理器
strmqm QmgrName
如果是启动默认的队列管理器,可以不带其名字

停止队列管理器
endmqm QmgrName
受控停止

endmqm –i QmgrName
立即停止

endmqm –p QmgrName
强制停止

显示队列管理器
dspmq –m QmgrName

运行MQSeries命令
runmqsc QmgrName
如果是默认队列管理器,可以不带其名字

往队列中放消息
amqsput QName QmgrName
如果队列是默认队列管理器中的队列,可以不带其队列管理器的名字

从队列中取出消息
amqsget QName QmgrName
如果队列是默认队列管理器中的队列,可以不带其队列管理器的名字

启动通道
runmqchl –c ChlName –m QmgrName

启动侦听
runmqlsr –t TYPE –p PORT –m QMgrName

停止侦听
endmqlsr -m QmgrName

MQSeries
命令

定义死信队列
DEFINE QLOCAL
QNAME DEFPSISTYES REPLACE

设定队列管理器的死信队列
ALTER QMGR DEADQ
QNAME

定义本地队列
DEFINE QL
QNAME REPLACE

定义别名队列
DEFINE QALIAS(QALIASNAME) TARGQ(QNAME)

远程队列定义
DEFINE QREMOTE
QRNAME +
RNAME
AAA RQMNAMEQMGRNAME +
XMITQ
QTNAME

定义模型队列
DEFINE QMODEL
QNAME DEFTYPETEMPDYN

定义本地传输队列
DEFINE QLOCAL(QTNAME) USAGE(XMITQ) DEFPSIST(YES) +
INITQ
SYSTEM.CHANNEL.INITQ+
PROCESS(PROCESSNAME) REPLACE

创建进程定义
DEFINE PROCESS
PRONAME +
DESCR
‘STRING’+
APPLTYPE
WINDOWSNT+
APPLICID
’ runmqchl -c SDR_TEST -m QM_ TEST’
其中APPLTYPE的值可以是:CICSUNIXWINDOWSWINDOWSNT

创建发送方通道
DEFINE CHANNEL
SDRNAME CHLTYPESDR+
CONNAME
‘100.100.100.215(1418)’ XMITQQTNAME REPLACE
其中CHLTYPE可以是:SDRSVRRCVRRQSTRCLNTCONNSVRCONNCLUSSDRCLUSRCVR

创建接收方通道
DEFINE CHANNEL
SDR_ TEST CHLTYPERCVR REPLACE

创建服务器连接通道
DEFINE CHANNEL
SVRCONNNAME CHLTYPESVRCONN REPLACE

显示队列的所有属性
DISPLAY QUEUE
QNAME [ALL]

显示队列的所选属性
DISPLAY QUEUE
QNAME DESCR GET PUT
DISPLAY QUEUE
QNAMEMAXDEPTH CURDEPTH

显示队列管理器的所有属性
DISPLAY QMGR [ALL]

显示进程定义
DISPLAY PROCESS
PRONAME

更改属性
ALTER QMGR DESCR
‘NEW DESCRIPTION’
ALTER QLOCAL
QNAME PUTDISABLED
ALTER QALIAS
QNAME TARGQTARGQNAME

删除队列
DELETE QLOCAL
QNAME
DELETE QREMOTE
QRNAME

清除队列中的所有消息
CLEAR QLOCAL
QNAME



二.配置一个能够通信的远程连接
以上讲述了MQ的基本命令操作,但只知道这些是没有实际意义的。MQ的最终目的是实现远程通信,所以下面就以一个具体的例子来说明如何实现远程连接。这个例子的目的是建立可以实现消息传递的一对MQ服务器,它们分别基于NTUNIX平台。
首先在NT端建一队列管理器
crtmqm –q QM_NT
启动队列管理器
strmqm QM_NT
运行MQ控制台命令
runmqsc QM_NT
创建死信队列
DEFINE QL(NT.DEADQ) DEFPSIST(YES) REPLACE
更改队列管理器属性,设置其死信队列
ALTER QMGR DEADQ
NT.DEADQ
创建进程定义
DEFINE PROCESS
P_NT+
APPLTYPE
WINDOWSNT+
APPLICID
’ runmqchl -c SDR_NT -m QM_NT’
创建本地传输队列
DEFINE QL(QT_NT) USAGE(XMITQ) DEFPSIST(YES) +
INITQ
SYSTEM.CHANNEL.INITQ+
PROCESS(P_NT) REPLACE
创建远程队列定义,对应于UNIX机器上的本地队列Q_UNIX,传输队列为QT_NT
DEFINE QREMOTE
QR_NT+
RNAME
Q_UNIX RQMNAMEQM_UNIX+
XMITQ
QT_NT
创建发送方通道,其传输队列为QT_NT,远程主机地址为10.10.10.2,侦听端口为1414
DEFINE CHANNEL
SDR_NT CHLTYPESDR+
CONNAME
‘10.10.10.2(1414)’ XMITQQT_NT REPLACE
创建服务器连接通道
DEFINE CHANNEL
S_NT CHLTYPESVRCONN REPLACE

UNIX端创建队列管理器
crtmqm –q QM_UNIX
启动队列管理器
strmqm QM_UNIX
添加侦听程序
修改/etc/services文件,加入一行:
MQSeries 1414/tcp #MQSeries channel listener
修改/etc/inetd.conf文件,加入一行(启动侦听程序)
MQSeries stream tcp nowait mqm /usr/lpp/mqm/bin/amqcrsta amqcrsta –m QM_UNIX
运行以下命令,以使修改起作用
refresh –s inetd

运行MQ控制台命令
runmqsc QM_UNIX
创建死信队列
DEFINE QL(UNIX.DEADQ) DEFPSIST(YES) REPLACE
更改队列管理器属性,设置其死信队列
ALTER QMGR DEADQ
UNIX.DEADQ
创建接收方通道,其名字必须与远程发送方相同
DEFINE CHANNEL
SDR_NT CHLTYPERCVR REPLACE
创建本地队列
DEFINE QL
Q_UNIX DEFPSIST(YES) REPLACE
创建服务器连接通道
DEFINE CHANNEL
S_UNIX CHLTYPESVRCONN REPLACE

经过以上操作之后,远程连接的配置工作完成。接下来需要验证配置是否正确。
NT端启动发送方通道
runmqchl –c SDR_NT –m QM_NT
start chl(SDR_NT)
NT端发送消息到UNIX
amqsput QR_NT QM_NT
UNIX端接收消息
/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端的远程连接和以上相仿,要建立双向的传输网络也是同样的道理。

三.配置JNDI
JMS实现消息的发送和接收时,经常会用到JNDI。因为JNDI这种方式比较灵活,对于编程也比较简单。
在安装了MQSeries Client for Java之后,在/java/bin目录下找到JMSAdmin.config文件。该文件主要用来说明Context的存储方式及存储地址,对应于文件中的两个参数INITIAL_CONTEXT_FACTORYPROVIDER_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提供的,它需要和websphereCosNaming资源库一起使用。
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_PATHMQSeries Client for Java安装的根目录。
若启动失败,则好好检查一下您的环境变量是否设置正确。根据我个人的经验,除了把com.ibm.mq.jarcom.ibm.mqjms.jar加入到环境变量外,还要把fscontext.jarproviderutil.jar加入到环境变量。
进入JMSAdmin控制台后,您可以自由定义sub context。对于子上下文的操作,主要有一下命令:
display ctx
define ctx(ctxname)
change ctx(ctxname)
change ctx(=up)
change ctx(=init)
delete ctx(ctxname)

当然,在这里的主要任务并非是用来定义sub context,而是用来定义以下几个对象:
MQQueueConnectionFactory
MQTopicConnectionFactory
MQQueue
MQTopic
(还有其它的一些对象,如MQXAQueueConnectionFactory等,不常用到,在此不作说明。)
可以使用很多动词来操纵目录名称空间中的受管理对象。ALTERDEFINEDISPLAYDELETECOPYMOVE,它们的用法都算比较简单,这里只列举一二以作说明。
例一:定义一QueueConnectionFactory,连接主机10.10.10.18,端口1414
DEFINE QCF(EXAMPLEQCF)+
DESC(Example Queue Connection Factory)+
TRAN(CLIENT)+
HOST(10.10.10.18)+
QMGR(QM_EXAMPLE)+
CHAN(S_EXAMPLE)+
PORT(1414)+
CCSID(1381)

例二:定义一Queue,其对应于MQ中的Q_EXAMPLE
DEFINE Q(EXAMPLEQL)+
DESC(Local queue)+
QMGR(QM_EXAMPLE)+
QUEUE(Q_EXAMPLE)+
CCSID(1381)

四.用JMS实现MQ编程
上面我们说明了怎样用JMSAdmin Tool定义MQ对象的上下文。我们的最终目的是要用JMS来实现MQ编程,以实现在程序中对MQ队列进行收、发消息。所以,下面我们将重点讨论一下MQJMS实现。
如果您对JMS编程很熟悉,那么您也就会用JMS来实现MQ编程,因为用JMS来编写MQ程序与编写一般的JMS程序没有太大的差别。举个例子,当我们想发送一条消息到MQ的队列中,再从该队列中取回消息时,我们编程时主要有四个步骤。首先我们要初始化在程序中要用到的对象,然后才可以发送消息到队列中去,再就是收取消息了,最后要清除那些永久对象。这些都和普通的JMS程序相当。程序的源代码如下:

import java.util.Hashtable;
import javax.jms.*;
import javax.naming.*;
import javax.naming.directory.*;

public class sample {
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);
Queue q1=null;
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);
connection.start();
}
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 {
queueSession.close();
connection.close();
}

public static void main(String[] args){
String rec;
sample sp = new sample();
try {
sp.sampleInit();
sp.sendMessageOut("Hello World!");
java.lang.Thread.sleep(4000);
rec=sp.receiveMessage();
System.out.println("Receive text is : "+rec);
sp.sampleClose();
}catch(Exception e) {
e.printStackTrace();
}
}
}

五.远程管理
MQ
WINDOWS平台下具有图形化管理界面,但在UNIX平台下却只能通过命令行来进行操作。这样就给使用者带来很大的不便。我们都希望能通过图形界面来进行管理配置。为了实现我们的想法,我们就必须建立远程管理。
实现远程管理有以下几个步骤:
1
.被管理队列管理器上的命令队列SYSTEM.ADMIN.COMMAND.QUEUE存在并可用。对于MQ 2版本应执行 amqscoma.tst 脚本来创建。
2
.使用strmqcsv命令来启动被管理队列管理器上的命令服务器。
3
.确定被管理队列管理器上的服务器连接通道SYSTEM.ADMIN.SVRCONN是否存在,如果不存在则创建它。
4
.一般UnixLinux平台中MQ默认的字符集为819,而Windows平台为1381,所以你必须改变其字符集,使两边的字符集相同。一般改被管理的字符集。
5
.如果被管理队列管理器上的操作用户与管理队列管理器上的操作用户不同,那么你首先要确认管理队列管理器上的操作用户在被管理队列管理器上存在并且有管理MQ的权限,再者,你需要修改服务器连接通道SYSTEM.ADMIN.SVRCONNMCAUSER属性为管理队列管理器上的操作用户。
6
.启动被管理队列管理器上的侦听器。

做完这些工作之后,直接在管理队列管理器的MQ管理工具中显示被管理队列管理器即可。然后你就可以象操作本地队列管理器一样,在被管理队列管理器上定义你需要的MQ对象。

六.通道维护
在配置远程连接的时候,我们曾经创建过进程定义。那我们为什么要去创建进程定义呢?这就涉及MQ通道维护的概念。
通道长时间没有消息触发就会自动断开连接,不再保持运行状态。时间的长短可以由自己设定,默认值为6000秒。消息请求再次来临的时候,就必须再次启动通道。有些通道,如服务器连接通道、接收方通道等是自动触发启动的。当消息请求发送到通道后,通道立即启动,进入运行状态。但也有一些通道不会自动启动,最典型的就是发送方通道。当有消息请求需要使用通道进行消息传递的时候,发送方通道也不会自动启动并把消息发送到远程队列,而是把消息留在了与其相关联的传输队列中。
但是,在实际应用中我们又不可能每过一段时间去启动一次通道,或当有消息来再去启动通道。那应该怎么办?首先我们创建一个进程定义,这个进程定义的目的就是用来启动发送方通道。然后我们在传输队列的进程名称属性栏指定刚才定义的进程定义名称,再把触发器控制开关打开。这样,当有消息进入传输队列后,传输队列的触发器会启动触发执行指定的进程,从而启动发送方通道,把消息传输到远程队列中去。