ActiveMQ异步投递

同步与异步

同步发送

异步发送时很多模式下的默认传输方式,但是发送非事务持久化消息的时候默认使用同步发送模式。同步发送时,Producer.send()方法会被阻塞,知道broker发送一个确认消息给生产者,这个确认消息提示生产者broker已成功将消息路由到目标并把消息保存到二级存储中

同步发送持久消息可以提供更好的可靠性,但是潜在影响了程序的响应速度,因为在接收到broker的确认消息之前应用程序或线程回被阻塞。如果应用程序能够容忍一些消息的丢失,可以使用异步发送。异步发送不会在收到broker的确认前一直阻塞。

异步发送

使用异步发送可以提高系统性能。在大多数情况下,ActiveMQ都以异步默认发送消息
例外:在没有使用事务的情况下,生产者以PERSISTENT传送模式发送消息。这种情况下Send方法都是同步的,并且一直阻塞到ActiveMQ发回确认消息。这种确认机制保证消息不会丢失,但会造成生产者阻塞从而影响反应时间。高性能程序一般都能容忍在故障情况下丢失少量数据,可以通过使用异步发送在提高吞吐量。

演示

开启异步投送

启用异步发送需要生产者设置UseAsyncSend=true
这里演示两种方式设置它

 // 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        
        // 在连接工厂中设置异步投递
        activeMQConnectionFactory.setUseAsyncSend(true);
        
        // 创建连接
        ActiveMQConnection connection = null;
        connection = (ActiveMQConnection)activeMQConnectionFactory.createConnection();
        // 在创建的连接对象中开启异步投递(需要使用ActiveMQConnection)
        connection.setUseAsyncSend(true);

丢失消息的场景

			connection.setUseAsyncSend(true);  //开启异步投递
			session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            Queue queue = session.createQueue("Queue-Async");
            ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            for (int i = 1; i <= 3; i++) {
                TextMessage message = session.createTextMessage("Message ==> " + i);
                producer.send(message);
            }
            // 如果开启事务,则需要在会话关闭前手动提交事务
            session.commit();

以上代码中设置了异步投递但发送是生产者使用producer.send(message);持续发送消息。由于消息不阻塞,生产者会认为所有send消息均被发送成功至MQ。如果服务器突然宕机,此时生产者端内存中尚未发送到MQ的消息将全部丢失。正确的异步发送方法是需要接收回调的。

异步投递确保MQ收到消息

正确的异步发送方法是需要接收回调的
producer.send中有带有AsyncCallback的方法。

public void send(Message message, AsyncCallback onComplete) throws JMSException

该方法需要重写onSuccess方法和onException方法。

  • onSuccess():表示这条消息成功发送到了MQ上,并且接收到了MQ持久化后的回调。
  • onException():MQ返回一个入队异常的回执。

生产者代码示例

public class JmsProduce_AsyncSend {
    public static final String ACTIVEMQ_URL = "nio://192.168.100.110:61608";
    // public static final String ACTIVEMQ_URL = "tcp://localhost:61616";

    // public static final String ACTIVEMQ_URL = "failover:(tcp://host110:61616,tcp://host111:61616,tcp://host112:61616)?randomize=false";
    public static final String QUEUE_NAME = "queue01-Cluster";

    public static void main(String[] args) {
        // 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        // 创建连接
        ActiveMQConnection connection = null;
        Session session = null;
        try {
            connection = (ActiveMQConnection)activeMQConnectionFactory.createConnection();
            // 开启异步投递
            connection.setUseAsyncSend(true);
            log.info("连接创建");
            // 开启连接
            connection.start();
            log.info("连接启动");
            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            // 创建目的地
            Queue queue = session.createQueue(QUEUE_NAME);
            // 使用ActiveMQMessageProducer创建消息生产者
            ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue);
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 使用消息生产者,生产三条消息发送到MQ队列
            for (int i = 1; i <= 3; i++) {
                // 创建消息
                TextMessage message = session.createTextMessage("Cluster-Message ==> " + i);
                // 设置消息ID
                message.setJMSMessageID(UUID.randomUUID().toString() + "--orderXJY");
                // 通过消息生产者发布
                String msgID = message.getJMSMessageID();
                producer.send(message, new AsyncCallback() {
                    @Override
                    public void onSuccess() {
                        System.out.println(msgID + "====> Success");
                    }

                    @Override
                    public void onException(JMSException e) {
                        System.out.println(msgID + "====> Failed");
                    }
                });
            }
            // 如果开启事务,则需要在会话关闭前手动提交事务
            session.commit();
        } catch (JMSException e) {
            try {
                if (session != null) {
                    session.rollback();
                }
            } catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        } finally {
            if (session != null) {
                try {
                    session.close();
                    connection.close();
                } catch (JMSException e) {
                    System.exit(1);
                }
            }
        }

        log.info("连接断开");
    }
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JAVA小菜鸡223

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值