第四章 实验三IBM MQ测试高可用,使用连接工厂(多地址连接方式)

一、实验前言

场景三:测试高可用,使用连接工厂(多地址连接方式),不通过虚地址实现单节点故障后自动连接备用节点(QMRGRECGC->QMFX)
目的:1.实现主节点故障后能够自动重连到备用节点实现消息不丢失,服务高可用

该架构图与实验二的架构图在两个网关前减少了HA的高可用软件。
在这里插入图片描述

具体不一样的是场景三不使用Keepalived作为高可用服务,而采用IBM MQ提供的连接工厂方式,实现程序的主备切换。

二、实验步骤

2.1队列管理器配置

各个队列管理的配置跟实验场景二一样,这里不再重复。

2.2启动回执发送程序

在这里插入图片描述

2.3模拟主网关故障

在程序运行过程中停止主网关的客户端连接通道MY.SVRCONN

在这里插入图片描述
停止之后,程序应该会抛出异常,并发起重连

已发送:15
已发送:16
已发送:17
已发送:18
====有异常=====
com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ2007: 将消息发送至目标 'TO.HUIZHI' 失败。
JMS 尝试执行 MQPUT 或 MQPUT1;然而 WebSphere MQ 报告了错误。
使用链接的异常来确定此错误的原因。
	at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:578)
	at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:214)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1157)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1114)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer.access$800(WMQMessageProducer.java:72)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:843)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer$ProducerShadow.send(WMQMessageProducer.java:521)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer.send(WMQMessageProducer.java:1283)
	at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendMessage(JmsMessageProducerImpl.java:838)
	at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.synchronousSendInternal(JmsMessageProducerImpl.java:1967)
	at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendInternal(JmsMessageProducerImpl.java:1913)
	at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.send(JmsMessageProducerImpl.java:1469)
	at com.ibm.mq.jms.MQMessageProducer.send(MQMessageProducer.java:293)
	at com.datatech.jmstest.Test_CF.sendMsg2(Test_CF.java:202)
	at com.datatech.jmstest.Test_CF.main(Test_CF.java:171)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ 调用失败,完成代码为 '2' ( 'MQCC_FAILED' ),原因为 '2009' ( 'MQRC_CONNECTION_BROKEN' )。
	at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:202)
	... 13 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009
	at com.ibm.mq.jmqi.remote.impl.RemoteSession.getConnection(RemoteSession.java:494)
	at com.ibm.mq.jmqi.remote.impl.RemoteSession.getMaximumMessageLength(RemoteSession.java:1802)
	at com.ibm.mq.jmqi.remote.api.RemoteFAP.jmqiPutMessageWithProps(RemoteFAP.java:9860)
	at com.ibm.mq.jmqi.remote.api.RemoteFAP.jmqiPut(RemoteFAP.java:8968)
	at com.ibm.mq.ese.jmqi.InterceptedJmqiImpl.jmqiPut(InterceptedJmqiImpl.java:624)
	at com.ibm.mq.ese.jmqi.ESEJMQI.jmqiPut(ESEJMQI.java:636)
	at com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:831)
	... 9 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2202
	at com.ibm.mq.jmqi.remote.impl.RemoteRcvThread.run(RemoteRcvThread.java:441)
	at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.runTask(WorkQueueItem.java:263)
	at com.ibm.msg.client.commonservices.workqueue.SimpleWorkQueueItem.runItem(SimpleWorkQueueItem.java:99)
	at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.run(WorkQueueItem.java:284)
	at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.runWorkQueueItem(WorkQueueManager.java:312)
	at com.ibm.msg.client.commonservices.j2se.workqueue.WorkQueueManagerImplementation$ThreadPoolWorker.run(WorkQueueManagerImplementation.java:1193)
已发送:19
已发送:20
已发送:21
已发送:22
已发送:23
已发送:24
已发送:25
已发送:26
已发送:27
已发送:28
已发送:29

在代码
在这里插入图片描述

2.4 确认消息发送和接收数量

发动100个消息后程序停止,在主网关故障切换到备网关后,消息发送没有发生丢失,并正常发送。

在这里插入图片描述

三、结论

使用连接工厂方式可以减少高可用架构时候不用第三方的高可用软件,借用IBM MQ自身的方式就可以达到效果,减少一个环节就少一份风险,该代码还有很多优化的空间,本次只是测试是否能达到高可用服务状态,通过实验证明可以达到要求。
该代码中使用的是com.ibm.mq.jms.MQQueueConnectionFactory连接类

附:连接工厂方式测试代码

package com.datatech.jmstest;

import java.io.IOException;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;

import com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.MQConstants;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;

public class Test_CF {
	    static MQQueueManager qMgr;
	    static int CCSID = 1381;
	    static String queueString = "TO.HUIZHI";
	    static int openOptions = MQConstants.MQOO_OUTPUT | MQConstants.MQOO_FAIL_IF_QUIESCING;
	     static MQQueue queue = null;
	    public static void connect() throws MQException {
	    	MQEnvironment.hostname = "192.168.153.200";// MQ服务器IP      
	        MQEnvironment.channel = "MY.SVRCONN";     // 队列管理器对应的服务器连接通道      
	        MQEnvironment.CCSID = 1381;            // 字符编码      
	        MQEnvironment.port = 1417;             // 队列管理器的端口号      
//	        //MQ中拥有权限的用户名
	        MQEnvironment.userID = "mqm";
	        //用户名对应的密码
	        MQEnvironment.password = "123456";
	        try {      
	            qMgr = new MQQueueManager("QMRGRECGC");// 队列管理器名称      
	            queue = qMgr.accessQueue(queueString, openOptions, null, null, null);
	        } catch (MQException e) {      
	            e.printStackTrace();      
	        }      

	    }

	    public static void sendMsg(String msgStr) {
	    	 //设置将要连接的队列属性
            //目标为远程队列,所有这里不可以用MQOO_INPUT_AS_Q_DEF属性
            //int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT;
            //以下选项可适合远程队列与本地队列
            
            //连接队列
            //MQQueue provides inquire, set, put and get operations for WebSphere MQ queues.
            //The inquire and set capabilities are inherited from MQManagedObject.
             /*关闭了就重新打开*/
	       
	        
	            // 建立Q1通道的连接
	           
	            MQMessage msg = new MQMessage();// 要写入队列的消息
	            msg.format = MQConstants.MQFMT_STRING;
	            msg.characterSet = CCSID;
	            msg.encoding = CCSID;
	           
	           
	            // msg.writeObject(msgStr); //将消息写入消息对象中;
	            boolean Flag;
	            Flag=true;
	            int count=1;
	            while(Flag)
	            {
	            try {
	            MQPutMessageOptions pmo = new MQPutMessageOptions();
	 	        msg.expiry = -1; // 设置消息用不过期
	            msg.writeString(msgStr);
	           
	            queue.put(msg, pmo);// 将消息放入队列
	            }catch(java.net.SocketException e){
	            	System.out.println("网络故障,正在切换备用服务");
	            } catch(IOException e){
	            	System.out.println("IO故障");
	            	//msg.writeString(msgStr);
	            } 
	             catch (MQException e) {
	            	 System.out.println("===="+e.getCompCode()+"============");
	            	 System.out.println("====网络故障,正在切换备用服务============");
	            	 try {
						connect();
						 MQPutMessageOptions pmo = new MQPutMessageOptions();
				 	        msg.expiry = -1; // 设置消息用不过期
				            try {
								msg.writeString(msgStr);
							} catch (IOException e1) {
								// TODO Auto-generated catch block
								e1.printStackTrace();
							}
						 queue.put(msg, pmo);// 将消息放入队列
					} catch (MQException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
	            	 
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		
		        } 
	            finally {
	            	
	            	
	            }
	            System.out.println("已发送:"+count);
	            count++;
	            try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	            }

	            if (queue != null) {
	                try {
	                    queue.close();
	                } catch (MQException e) {
	                	
	                    // TODO Auto-generated catch block
	                    e.printStackTrace();
	                }
	        }
	    }

	    public static void receiveMsg() {
	        int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT | MQC.MQOO_INQUIRE;
	        MQQueue queue = null;
	        try {
	            queue = qMgr.accessQueue(queueString, openOptions, null, null, null);
	            System.out.println("该队列当前的深度为:" + queue.getCurrentDepth());
	            System.out.println("===========================");
	            int depth = queue.getCurrentDepth();
	            // 将队列的里的消息读出来
	            while (depth-- > 0) {
	                MQMessage msg = new MQMessage();// 要读的队列的消息
	                MQGetMessageOptions gmo = new MQGetMessageOptions();
	                queue.get(msg, gmo);
	                System.out.println("消息的大小为:" + msg.getDataLength());
	                System.out.println("消息的内容:\n" + msg.readStringOfByteLength(msg.getDataLength()));
	                System.out.println("---------------------------");
	            }
	        } catch (Exception e) {
	            // TODO Auto-generated catch block
	            e.printStackTrace();
	        } finally {
	            if (queue != null) {
	                try {
	                    queue.close();
	                } catch (MQException e) {
	                    // TODO Auto-generated catch block
	                    e.printStackTrace();
	                }
	            }
	        }
	    }

	    public static void main(String[] args) throws MQException {
	        connect();
	        sendMsg2("我来测试一下");

	      //  receiveMsg();
	    }

	    public static void sendMsg2(String msg)
	    {
	        MQQueueConnectionFactory connectionFactory = null;
	        QueueConnection queueConn = null;
	        QueueSession queueSession = null;
	        QueueSender queueSender = null;
	        TextMessage message = null;

	        try
	        {
	        	System.out.println("===进入========");
	            connectionFactory = new MQQueueConnectionFactory();
	            connectionFactory.setConnectionNameList("192.168.153.128(1417), 192.168.153.129(1417)");
	            connectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
	            connectionFactory.setQueueManager("QMRGRECGC");
	            connectionFactory.setChannel("MY.SVRCONN"); 
	            queueConn = connectionFactory.createQueueConnection("mqm","123456");
	            queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 
	            queueSender = queueSession.createSender(queueSession.createQueue("TO.HUIZHI"));  
	            queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);  
	            message = queueSession.createTextMessage(msg);
	            message.setJMSCorrelationID("12345");
	            int count=1;
	           while(true){
	        	 try{
	            queueSender.send(message);    
	            System.out.println("已发送:"+count);
	            count++;
	            Thread.sleep(2000);
	        	 } catch (Exception e)
	 	        {
	        		  System.out.println("====有异常=====");
	        		 queueConn = connectionFactory.createQueueConnection("mqm","123456");
	 	            queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 
	 	            queueSender = queueSession.createSender(queueSession.createQueue("TO.HUIZHI"));  
	 	            queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);  
	 	            message = queueSession.createTextMessage(msg);
	 	            message.setJMSCorrelationID("12345");
	 	           queueSender.send(message);    
	 	          System.out.println("已发送:"+count);
		            count++;
	 	        }
	           }
	        } 
	       
	        catch (Exception e)
	        {
	            e.printStackTrace();
	        }finally{
	        	
	        	  if (queue != null) {
		                try {
		                	queueSender.close();
		                    queue.close();
		                } catch (MQException e) {
		                	
		                    // TODO Auto-generated catch block
		                    e.printStackTrace();
		                } catch (JMSException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
		        }
	        }
	        
	    }  
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值