如何从Websphere MQ读取大量消息

时间:2015-10-11 14:09:40

标签: jms ibm-mq messaging mq

我希望按顺序从组中读取来自Websphere MQ的10000条消息,我使用下面的代码来执行相同操作,但是需要很长时间才能读取所有消息。即使我试图使用多线程概念,但有时2个线程正在消耗相同的组和竞争条件发生。以下是代码段。 我试图使用3个线程从MQ顺序读取10000条消息,但我的两个线程在时间访问同一组。怎么避免这个?什么是顺序读取大量消息的最佳方法。我的要求是我想按顺序读取10000条消息。请帮忙。

MQConnectionFactory factory = new MQConnectionFactory();
factory.setQueueManager("QM_host")
MQQueue destination = new MQQueue("default");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

MessageConsumer lastMessageConsumer = 
    session.createConsumer(destination, "JMS_IBM_Last_Msg_In_Group=TRUE");
TextMessage lastMessage = (TextMessage) lastMessageConsumer.receiveNoWait();
lastMessageConsumer.close();

if (lastMessage != null) {

    int groupSize = lastMessage.getIntProperty("JMSXGroupSeq");
    String groupId = lastMessage.getStringProperty("JMSXGroupID");

    boolean failed = false;

    for (int i = 1; (i < groupSize) && !failed; i++) {

        MessageConsumer consumer = session.createConsumer(destination,
            "JMSXGroupID='" + groupId + "'AND JMSXGroupSeq=" + i);
        TextMessage message = (TextMessage)consumer.receiveNoWait();

        if (message != null) {
            System.out.println(message.getText());
        } else {
            failed = true;
        }

        consumer.close();

    }

    if (failed) {
        session.rollback();
    } else {
        System.out.println(lastMessage.getText());
        session.commit();
    }

}

connection.close();

3 个答案:

答案 0 :(得分:0)

我认为更好的方法是在你的应用程序中有一个协调器线程,它将监听组的最后消息,并且每个消息都会启动一个新线程来获取属于分配给该线程的组的消息。 (这将迎合竞争条件。)

在获取属于组的消息的线程中,您不需要使用for循环来单独获取每条消息,而是应该接收属于该组的任何消息,同时维护组计数器并缓冲掉订单消息。只要您在接收并处理该组的所有消息后提交会话,这将是安全的。 (这将产生更多性能,因为每个组将由单独的线程处理,并且该线程将仅在MQ中访问每个消息一次。)

答案 1 :(得分:0)

请参阅有关sequential retrieval of messages的IBM文档。如果页面移动或更改,我将引用最相关的部分。为了保证顺序处理,必须满足以下条件

  • 所有看跌请求均来自同一个应用程序。
  • 所有看跌请求来自同一工作单元,或者所有看跌请求都是在一个工作单元之外进行的。
  • 消息都具有相同的优先级。
  • 这些消息都具有相同的持久性。
  • 对于远程排队,配置是这样的,只有一个路径来自应用程序发出put请求,通过它 队列管理器,通过相互通信,到目标队列 经理和目标队列。
  • 消息不会被置于死信队列中(例如,如果队列暂时满了)。
  • 获取消息的应用程序不会故意更改检索顺序,例如通过指定特定的MsgId 或CorrelId或使用消息优先级。
  • 只有一个应用程序正在执行get操作以从目标队列中检索消息。如果有多个 应用程序,这些应用程序必须设计为获得所有 发送应用程序发出的每个序列中的消息。

虽然页面没有明确说明,但当他们说'#34;一个应用程序&#34;是什么意思是该应用程序的单个线程。如果应用程序具有并发线程,则无法保证处理顺序。

此外,按照另一个响应中的建议,在单个工作单元中读取10,000条消息 ,建议将其作为保留消息顺序的方法!只有当10,000条消息 必须 成功或失败为原子单位时才这样做,这与它们是否按顺序接收无关。如果必须在单个工作单元中处理大量消息,则必须调整日志文件的大小,并且很可能调整其他一些参数。保留序列顺序对于任何线程异步消息传输都是足够的折磨,而不会引入运行很长时间的大量事务。

答案 2 :(得分:0)

您可以使用MQ类for Java(非JMS)执行所需的操作,并且可以使用MQ类进行JMS,但实际上非常棘手。

首先从MQ Knowledge中读取此page

我将伪代码(从上面的网页)转换为Java的MQ类,并将其从浏览更改为破坏性获取。

另外,我更喜欢在同步点下进行每组消息(假设组合小的组合)。

首先,您缺少GMO(GetMessageOptions)的'options'字段的几个标志,并且MatchOptions字段需要设置为'MQMO_MATCH_MSG_SEQ_NUMBER',这样所有线程将始终抓取组中的第一条消息第一条消息。即如上所述,不要抓取第一条消息的组中的第二条消息。

MQGetMessageOptions gmo = new MQGetMessageOptions();
MQMessage rcvMsg = new MQMessage();

/* Get the first message in a group, or a message not in a group */
gmo.Options = CMQC.MQGMO_COMPLETE_MSG | CMQC.MQGMO_LOGICAL_ORDER | CMQC.MQGMO_ALL_MSGS_AVAILABLE | CMQC.MQGMO_WAIT | CMQC.MQGMO_SYNCPOINT;
gmo.MatchOptions = CMQC.MQMO_MATCH_MSG_SEQ_NUMBER;
rcvMsg.messageSequenceNumber = 1;
inQ.get(rcvMsg, gmo);

/* Examine first or only message */
 ...

gmo.Options = CMQC.MQGMO_COMPLETE_MSG | CMQC.MQGMO_LOGICAL_ORDER | CMQC.MQGMO_SYNCPOINT;
do while ((rcvMsg.messageFlags & CMQC.MQMF_MSG_IN_GROUP) == CMQC.MQMF_MSG_IN_GROUP)
{
    rcvMsg.clearMessage();
    inQ.get(rcvMsg, gmo);
   /* Examine each remaining message in the group */
   ...
}
qMgr.commit();