我在IBM MQ7和suse9的环境下做的开发。
我在发送一个大文件消息时,使用分段的方式进行操作,处理完成后放到远程队列当中,到达下一个目的地。
如果基于单独的mq的队列管理,如上的方法没有问题。但如果通过远程队列放到一个集群当中时,就会把一个完整的消息体四分五裂。在网上找N多资料,大都是要使用BIND_ON_OPEN做为打开的options。但每次都不管用。
说下具体情况。
QM_FIRST 表示要发送的队列管理器
QM_PROXY 表示集群的代理服务器,也是一个队列管理器,属于集群ANT
QM_EXE1 一个队列管理器,属于集群ANT,权重25%
QM_EXE2 一个队列管理器,属于集群ANT,权重25%
QM_EXE3 一个队列管理器,属于集群ANT,权重25%
QM_EXE4 一个队列管理器,属于集群ANT,权重25%
QM_FIRST通过对象UR_FIRST_TO_PROXY来完成于PROXY的发送。
目前的效果。
想要达到的效果。
说明一下,远程队列的使用方式,远程队列通过一个别名队列QM_PROXY_ALIAS放在集群当中的本地队列当中。
经过反复的论证和测试,发现这个问题的罪魁祸首就是这个远程队列,最后的解决方法是,弃用这个远程队列,直接连接到对方的集群当中的本地队列,也就是如上图的远程队列里。就可以了。
没有代码哟。大家可以自己直接写,比较简单,
部分代码示例。
private int SINGLE_MSG_MAX_LENGTH = 1048576; // 1M 默认是1M
/** * 分段发送文件. * * @param b * @param queueName * @throws QueueAccessException */ @SuppressWarnings("deprecation") public void putMessageMultiple(byte[] b, String queueName) throws QueueAccessException { MQQueue mqPut = null; try { mqPut = getPutQueue(queueName); int length, m, n; int packNum; length = b.length; m = length / SINGLE_MSG_MAX_LENGTH; n = length % SINGLE_MSG_MAX_LENGTH; if (n == 0) { packNum = m; } else { packNum = m + 1; } // second, put the msg to queue // 设置放消息时的参数 for (int packCount = 1; packCount <= packNum; packCount++) { MQMessage myMsg = new MQMessage(); MQPutMessageOptions pmo = new MQPutMessageOptions(); pmo.options = MQC.MQPMO_LOGICAL_ORDER + MQC.MQPMO_SYNCPOINT; if (packCount == packNum) { myMsg.messageFlags = MQC.MQMF_LAST_SEGMENT; if (n == 0) { myMsg.write(b, (packCount - 1) * SINGLE_MSG_MAX_LENGTH, SINGLE_MSG_MAX_LENGTH); } else { myMsg.write(b, (packCount - 1) * SINGLE_MSG_MAX_LENGTH, n); } } else { myMsg.messageFlags = MQC.MQMF_SEGMENT; myMsg.write(b, (packCount - 1) * SINGLE_MSG_MAX_LENGTH, SINGLE_MSG_MAX_LENGTH); } mqPut.put(myMsg, pmo); } } catch (MQException e) { if (e.completionCode == MQException.MQCC_FAILED && e.reasonCode == MQException.MQRC_UNKNOWN_OBJECT_NAME) { throw new InvalidQueueException(queueName + " MQException occur when getting the messsage.", e); } else { throw new QueueAccessException(queueName + " MQException occur when sending the messsage.", e); } } catch (IOException e) { throw new QueueAccessException(queueName + " IOException occur when sending the messsage.", e); } }
/** * 得到发送消息队列的实例 */ @SuppressWarnings("deprecation") private MQQueue getPutQueue(String queueName) throws MQException { MQQueue queue = null; queue = (MQQueue) putQueues.get(queueName); if (queue == null) { int openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING; queue = qMgr.accessQueue(queueName, openOptions); putQueues.put(queueName, queue); } return queue; }
如上只是发送的代码。
如下是取出的代码。
/** * 从队列中浏览分段消息 * * @param queueName * @return byte[] * @roseuid 447FA30301A0 */ @SuppressWarnings("deprecation") public byte[] browseBigMessage(String queueName) throws QueueAccessException { byte[] b = null; byte[] retbb = null; ByteArrayOutputStream out = null; MQQueue browseQueue = null; try { browseQueue = getBrowseQueueBySeq(queueName); out = new ByteArrayOutputStream(); MQMessage inMsg; // 设置取消息时的参数 MQGetMessageOptions gmo = new MQGetMessageOptions(); gmo.options = MQC.MQGMO_LOGICAL_ORDER + MQC.MQGMO_SYNCPOINT + MQC.MQGMO_ALL_SEGMENTS_AVAILABLE; boolean isLastSegment = false; while (!isLastSegment) { inMsg = new MQMessage(); browseQueue.get(inMsg, gmo); if (inMsg.messageFlags == MQC.MQMF_SEGMENT + MQC.MQMF_LAST_SEGMENT) isLastSegment = true; b = new byte[inMsg.getMessageLength()]; inMsg.readFully(b); out.write(b); out.flush(); b = null; } retbb = out.toByteArray(); } catch (MQException e) { if (e.completionCode == MQException.MQCC_FAILED && e.reasonCode == MQException.MQRC_UNKNOWN_OBJECT_NAME) { throw new InvalidQueueException(queueName + " MQException occur when browsing the messsage.", e); } else if (!(e.completionCode == 2 && e.reasonCode == 2033)) { throw new QueueAccessException(queueName + " MQException occur when browsing the messsage.", e); } } catch (IOException e) { throw new QueueAccessException(queueName + " IOException occur when browsing the messsage.", e); } catch (NumberFormatException e) { throw new QueueAccessException(queueName + " NumberFormatException occur when browsing the messsage.", e); } return retbb; } /** * 得到浏览消息队列的实例,分段时实用 */ @SuppressWarnings("deprecation") private MQQueue getBrowseQueueBySeq(String queueName) throws MQException { MQQueue queue = null; queue = (MQQueue) browseQueues.get(queueName); if (queue == null) { int openOptions = MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING | MQC.MQOO_INQUIRE;// 本属性是browse and queue = qMgr.accessQueue(queueName, openOptions); browseQueues.put(queueName, queue); } return queue; }
呵呵。