Java 将消息异步放置在WebSphere MQ队列上

Java 将消息异步放置在WebSphere MQ队列上,java,asynchronous,ibm-mq,put,Java,Asynchronous,Ibm Mq,Put,我试图将持久性消息放入WebSphereMQ队列,但是这些消息需要是异步的。我似乎能够使异步工作的唯一方法是,如果消息是非持久性的,那么我的意思是putSuccessCount等于放置在MQAsyncStatus上的消息数,所有其他时间都为零。下面的代码概述了我正在尝试执行的操作: import com.ibm.mq.MQAsyncStatus; import com.ibm.mq.MQDestination; import com.ibm.mq.MQMessage; import com.ib

我试图将持久性消息放入WebSphereMQ队列,但是这些消息需要是异步的。我似乎能够使异步工作的唯一方法是,如果消息是非持久性的,那么我的意思是putSuccessCount等于放置在MQAsyncStatus上的消息数,所有其他时间都为零。下面的代码概述了我正在尝试执行的操作:

import com.ibm.mq.MQAsyncStatus;
import com.ibm.mq.MQDestination;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.MQConstants;

public class MQPutTest extends TestCase{

    private static Logger log = Logger.getLogger(MQPutTest.class);

    public void testPut() throws Exception{

        Hashtable<String, Object> props = new Hashtable<String, Object>();
        props.put(MQConstants.CHANNEL_PROPERTY, "my_channel");
        props.put(MQConstants.PORT_PROPERTY, 1414);
        props.put(MQConstants.HOST_NAME_PROPERTY, "localhost");

        String qManager = "my_queue_manager"; 
        MQQueueManager qMgr = new MQQueueManager(qManager, props);

        int openOptions = MQConstants.MQOO_OUTPUT | MQConstants.MQOO_INPUT_AS_Q_DEF;

        MQDestination queue = qMgr.accessQueue("my_queue", openOptions);

        MQPutMessageOptions pmo = new MQPutMessageOptions();
        pmo.options = MQConstants.MQPMO_ASYNC_RESPONSE;

        MQMessage message = new MQMessage();
        message.format = MQConstants.MQFMT_STRING;
        message.writeString("test message");
        queue.put(message, pmo);

        queue.close();
        MQAsyncStatus asyncStatus = qMgr.getAsyncStatus();
        qMgr.disconnect();
    }
}
我将看到的大量消息的性能提高归因于队列被设置为非持久性,而不是消息被异步放置。我已在MQ explorer中的队列扩展属性中将默认put响应类型设置为Asynchronous,但这没有效果


任何帮助都将不胜感激

如果可以丢失一条或两条消息,您可以将消息添加到内部发送队列,例如

ExecutorService service = Executors.newSingleThreadedExecutor();

// build you message here

// add the message to be sent asynchronously.
service.execute(new Runnable() {
    public void run() {
         queue.put(message, pmo);
    }
});

进程终止时队列中的任何消息都将丢失。

如果可以丢失一条或两条消息,则可以将消息添加到内部发送队列,例如

ExecutorService service = Executors.newSingleThreadedExecutor();

// build you message here

// add the message to be sent asynchronously.
service.execute(new Runnable() {
    public void run() {
         queue.put(message, pmo);
    }
});

进程终止时队列中的任何消息都将丢失。

根据问题中的注释,WMQ没有持久队列的概念,因此我更改了文章标题。持久性的队列属性不会以任何方式更改QMgr处理队列或其中任何消息的方式。它所做的只是告诉程序,如果程序员没有显式地设置该值,应该使用哪个持久性选项。任何给定消息是否持久取决于MQMD在消息首次放入队列时是否指定了持久性。任何队列都可以包含任意组合的持久消息和非持久消息

具体来说,post中的代码段没有使用message.setPersistence指定持久性,因此它将继承队列的默认值。这又取决于从队列属性继承的值。在任何情况下,队列属性设置都不会覆盖应用程序中的显式设置

因此,您所看到的性能差异实际上很可能反映了队列的DEFPSIST属性的设置,但这并不意味着异步put不起作用。请记住,异步放置不会以任何方式减少将消息放入队列所需的时间。QMgr具有相同的代码路径来持久化消息,无论put是否同步。不同之处在于,您的应用程序不再等待QMgr完成其工作。当您调用MQAsyncStatus更新时,WMQ完全可能尚未写入任何消息。如果它们都在单个工作单元中,则更可能出现这种情况,因为在提交处理完成之前,WMQ不会返回所有消息的状态。除非显式调用COMMIT,否则在关闭队列时会发生这种情况

您可以通过在提交或关闭后几秒钟内每秒重复qMgr.getAsyncStatus调用来验证这一点。您应该看到,第一个函数没有成功地返回任何消息,但最终您可以解释所有消息

顺便说一句,消息是否持久的问题几乎应该总是在代码中处理。消息持久性通常作为业务需求派生,并在应用程序的设计中捕获。因此,项目经理和开发人员有责任确保满足要求。可靠地确保满足该条件的唯一方法是应用程序显式调用setPErsistence。否则,应用程序将使用队列的DEFPSIST属性中的值隐式调用setPersistence。那么,为什么还要在API中允许这种默认设置呢?因为在一些合法的情况下,持久性需要能够在运行时更改。编写应用程序以故意采用默认值,并在每个工作单元完成后重新打开队列。在所有其他情况下,应在程序或托管对象中设置持久性

最后,如果要在单个工作单元下放置10000条消息,则可以得到一个响应,说明没有成功放置消息的另一个原因是缺少日志空间或未设置可调参数以适应负载。例如,如果MAXUMSGS设置为小于10000,则整个事务将回滚。另一方面,如果MAXUMSGS设置正确,但主日志和辅助日志的大小和数量不足以容纳事务中的数据量,那么整个事务将再次回滚。您应该稍微调整一下提交间隔,因为最佳值取决于消息大小与队列和日志缓冲区大小的关系。一旦超过了可以优化为单个写入操作的数据量,额外的消息实际上会降低性能。当人们把10000条信息放到一个工作单元中时,它就是ha
RDY永远都是为了性能,但因为这是他们合适的恢复单元,相应的性能命中率是恢复要求的次要因素。

根据问题中的评论,WMQ没有持久队列的概念,因此我更改了文章标题。持久性的队列属性不会以任何方式更改QMgr处理队列或其中任何消息的方式。它所做的只是告诉程序,如果程序员没有显式地设置该值,应该使用哪个持久性选项。任何给定消息是否持久取决于MQMD在消息首次放入队列时是否指定了持久性。任何队列都可以包含任意组合的持久消息和非持久消息

具体来说,post中的代码段没有使用message.setPersistence指定持久性,因此它将继承队列的默认值。这又取决于从队列属性继承的值。在任何情况下,队列属性设置都不会覆盖应用程序中的显式设置

因此,您所看到的性能差异实际上很可能反映了队列的DEFPSIST属性的设置,但这并不意味着异步put不起作用。请记住,异步放置不会以任何方式减少将消息放入队列所需的时间。QMgr具有相同的代码路径来持久化消息,无论put是否同步。不同之处在于,您的应用程序不再等待QMgr完成其工作。当您调用MQAsyncStatus更新时,WMQ完全可能尚未写入任何消息。如果它们都在单个工作单元中,则更可能出现这种情况,因为在提交处理完成之前,WMQ不会返回所有消息的状态。除非显式调用COMMIT,否则在关闭队列时会发生这种情况

您可以通过在提交或关闭后几秒钟内每秒重复qMgr.getAsyncStatus调用来验证这一点。您应该看到,第一个函数没有成功地返回任何消息,但最终您可以解释所有消息

顺便说一句,消息是否持久的问题几乎应该总是在代码中处理。消息持久性通常作为业务需求派生,并在应用程序的设计中捕获。因此,项目经理和开发人员有责任确保满足要求。可靠地确保满足该条件的唯一方法是应用程序显式调用setPErsistence。否则,应用程序将使用队列的DEFPSIST属性中的值隐式调用setPersistence。那么,为什么还要在API中允许这种默认设置呢?因为在一些合法的情况下,持久性需要能够在运行时更改。编写应用程序以故意采用默认值,并在每个工作单元完成后重新打开队列。在所有其他情况下,应在程序或托管对象中设置持久性


最后,如果要在单个工作单元下放置10000条消息,则可以得到一个响应,说明没有成功放置消息的另一个原因是缺少日志空间或未设置可调参数以适应负载。例如,如果MAXUMSGS设置为小于10000,则整个事务将回滚。另一方面,如果MAXUMSGS设置正确,但主日志和辅助日志的大小和数量不足以容纳事务中的数据量,那么整个事务将再次回滚。您应该稍微调整一下提交间隔,因为最佳值取决于消息大小与队列和日志缓冲区大小的关系。一旦超过了可以优化为单个写入操作的数据量,额外的消息实际上会降低性能。当人们将10000条消息放入一个工作单元时,这几乎不是为了性能,而是因为这是他们适当的恢复单元,相应的性能影响是恢复要求的次要因素。

后台发送的消息不会持久化,因为如果应用程序在恢复之前停止,它们可能会丢失消息已发送。知道消息已被持久化的唯一方法是等待消息以可恢复的方式被接受(通常写入服务器上的磁盘)。谢谢,那么在持久队列上是否可以使用fire和forget呢?我想做的是将消息发送到一个持久队列,以便它们在重新启动后生存,而不是等待队列管理器对每个PUT做出响应,我只想向队列管理器抛出消息,但不需要知道它们是否进入队列中。我可以使用MQAsyncStatus来协调每批消息之后的数字。这纯粹是出于性能原因

你们的问题是,要么你们需要担保,要么你们不需要担保。听起来,如果有一两条消息丢失了,但不是全部丢失了,您还可以吗?如果没有使用异步put持久化消息,则情况并非如此。异步put接受持久消息。此功能将放置持久消息的能力与放置状态的传递分离。PUT可能会失败,并且应用程序无法使用此传递方法获取通知,但WMQ将保留它异步获取的任何消息(如果请求)。此外,此处的测试用例无效。只有当应用程序正在流式传输许多消息时,异步put才有意义。由于close是一个阻塞调用,测试代码将永远看不到异步put的任何好处。在后台发送的消息不会持久化,因为如果应用程序在消息发送之前停止,它们可能会丢失。知道消息已被持久化的唯一方法是等待消息以可恢复的方式被接受(通常写入服务器上的磁盘)。谢谢,那么在持久队列上是否可以使用fire和forget呢?我想做的是将消息发送到一个持久队列,以便它们在重新启动后生存,而不是等待队列管理器对每个PUT做出响应,我只想向队列管理器抛出消息,但不需要知道它们是否进入队列中。我可以使用MQAsyncStatus来协调每批消息之后的数字。这纯粹是出于性能方面的原因。问题是要么需要担保,要么不需要担保。听起来,如果有一两条消息丢失了,但不是全部丢失了,您还可以吗?如果没有使用异步put持久化消息,则情况并非如此。异步put接受持久消息。此功能将放置持久消息的能力与放置状态的传递分离。PUT可能会失败,并且应用程序无法使用此传递方法获取通知,但WMQ将保留它异步获取的任何消息(如果请求)。此外,此处的测试用例无效。只有当应用程序正在流式传输许多消息时,异步put才有意义。因为close是一个阻塞调用,所以测试代码永远看不到异步put的任何好处?因为在v7.0中,本机异步PUT将此委托给QMgr,并且不会像上面的示例那样在PUT和CLOSE之间创建竞争条件。我认为在v7.0及以上版本中,开发人员使用本机函数会更好,但这将是一个很好的v6.0解决方案。我假设您仅在关闭应用程序时才会关闭连接。打开和关闭连接可能比创建/发送消息更昂贵。是的,但是如果您将多条消息分派给子线程,然后发出关闭,则会创建一个竞争条件,在该条件下,连接句柄可能会在子线程放入所有消息之前消失。虽然CLOSE在应用程序的生命周期中只发布一次,但需要对子线程进行一些管理以防止出现这种情况。否则,该方法几乎可以保证丢失至少一到两条消息。您可以将close添加为作业,这样就没有竞争条件。它不会立即关闭。您在考虑WMQV6.0,对吗?因为在v7.0中,本机异步PUT将此委托给QMgr,并且不会像上面的示例那样在PUT和CLOSE之间创建竞争条件。我认为在v7.0及以上版本中,开发人员使用本机函数会更好,但这将是一个很好的v6.0解决方案。我假设您仅在关闭应用程序时才会关闭连接。打开和关闭连接可能比创建/发送消息更昂贵。是的,但是如果您将多条消息分派给子线程,然后发出关闭,则会创建一个竞争条件,在该条件下,连接句柄可能会在子线程放入所有消息之前消失。虽然CLOSE在应用程序的生命周期中只发布一次,但需要对子线程进行一些管理以防止出现这种情况。否则,该方法几乎可以保证丢失至少一到两条消息。您可以将close添加为作业,这样就没有竞争条件。它只是不能立即关闭。