ActiveMQ - prefetch与optimizeACK

什么是prefetch

prefetch即在activemq中消费者预获取消息数量,重要的调优参数之一。当消费者存活时,broker将会批量push prefetchSize条消息给消费者,消费者也可以配合optimizeAcknowledge来批量确认它们。由于broker批量push消息给消费者,提高了网络传输效率,此值默认为1000。

通过上述,我们对broker消息转发机制的了解,可以知道,broker端将会根据consumer指定的prefetchSize来决定pendingBuffer的大小,prefetchSize越大,broker批量发送的消息就会越多,如果消费者消费速度较快,再配合optimizeAck,这将是相对完美的消息传送方案。

不过,prefetchSize也会带来一定的问题,在Queue中(Topic中没有效果),broker将使用“轮询”的方式来平衡多个消费者之间的消息传送数量。如果消费者消费速度较慢,而且prefetchSize较大,这将不利于消息量在多个消费者之间平衡。通常情况下,如果consumer数量较多,或者消费速度较慢,或者消息量较少时,我们应该设定prefetchSize为较小的值。

上面的内容摘抄:http://blog.csdn.net/asdfsadfasdfsa/article/details/53501723

其实,prefetchSize与optimizeACK策略关系密切,将在下一个介绍optimizeACK的小节中详细说明。

什么是optimizeACK

可优化的消息ACK策略,关系到是否批量确认消息的策略,这个是Consumer端最重要的调优参数之一。optimizeAcknowledge 表示是否开启“优化ACK选项”,当开启optimizeAck策略后,该参数的具体含义和消费端的处理如下:

(1)如果消费端处理消息的时间超过optimizeAcknowledgeTimeOut,消费端会向broker主动确认pending ack里面的消息,即等待确认的消息,这个与prefetch size有很大的关系,如果prefetch size为1,那么broker push到消费端的消息数会是1,那么在当前消息未完成处理的情况下,pending ack肯定是0,所以不会向broker确认消息。但是,假设prefetch size为5,broker推送到消费者的消息是5条,消费端在处理第3条消息的时候,耗时很长,导致5条消息的处理时候早早的超过了optimizeAcknowledgeTimeOut,此时,消费端将会把前面2条已经确认的消息,告诉broker,让broker从队列中删除消息,此时broker发现消费端还可以存放2个消息,又push两条消息到消费端。

(2)除了optimizeAcknowledgeTimeOut这个参数会使消费者触发批量确认消息,还有另一个指标,即,成功消费但待确认的消息数量超过 预取数量prefetchSize * 0.65 时,也会触发消费端自动确认那些待确认的消息。

验证

先了解一下activemq控制台

输入图片说明

  • Number Of Pending Messages : 是指broker等待发送到consumer的数量
  • Messages Enqueued :进行broker的消息总数量
  • Messages Dequeued :被consumer成功消费并且确认,已经从队列中删除的数量
  • Active Consumers:可以观察存活的consumer详情

下面看下consumer详情

输入图片说明

  • Prefetch:consumer的预取参数
  • Dispatched Queue :预取消息所存放的队列的大小,等待被consumer处理
  • Dispatched : 被broker分发到consumer的总数量
  • Dequeues :确认的消息数量

** 验证小技巧 **

(1)prefetchSize设为20,待producer发送200条消息到broker后,启动consumer,consumer每5秒处理一条消息,查看activemq的后台,看下consumer详情

(2)optimizeACK与optimizeAcknowledgeTimeOut、prefetchSize参数互调,观察后台结果。

请自行实验,结论已经在上面。

实验代码:https://git.oschina.net/thinwonton/activemq-showcase

sender

public class Sender {

    public static void main(String[] args) throws JMSException, InterruptedException {
        Connection connection = ActiveMQManager.createConnection();

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(Utils.QUEUE_NAME);
        MessageProducer producer = session.createProducer(queue);

        while (true) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
            for (int i = 0; i < 25; i++) {
                String date = dateFormat.format(new Date());
                String message = String.format("msg[%s][%s]", i, date);

                TextMessage toMessage = session.createTextMessage(message);
                producer.send(toMessage);
                System.out.println("消息发送成功:" + message);
            }

            Thread.sleep(30000); //10秒发送一批次
        }

    }
}

consumer

public class HighPrefetchSizeConsumer {
    public static void main(String[] args) throws IOException {
        try {
            ActiveMQConnection activeMQConnection = (ActiveMQConnection)ActiveMQManager.createConnection();
            ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy();
            prefetchPolicy.setQueuePrefetch(10);
            activeMQConnection.setPrefetchPolicy(prefetchPolicy); //预取策略
            activeMQConnection.setOptimizeAcknowledge(true); //可优化的ACK,延迟确认
            activeMQConnection.setOptimizeAcknowledgeTimeOut(1000);
            activeMQConnection.start();

            Session session = activeMQConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Queue queue = session.createQueue(Utils.QUEUE_NAME);
            MessageConsumer consumer = session.createConsumer(queue);

            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        System.out.println("-------- ----- --------- ");
                        System.out.println("触发消息接收");
                        TextMessage textMessage = (TextMessage) message;
                        String text = textMessage.getText();
                        handleMsg(text);
                        System.out.println("成功处理消息 : " + text);
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }

                }
            });

            System.out.println("is OptimizeAck:" + activeMQConnection.isOptimizeAcknowledge());
            System.out.println("OptimizeAck timeout:" + activeMQConnection.getOptimizeAcknowledgeTimeOut());


            // 线程一直等待
            System.in.read();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static void handleMsg(String msg) {
        System.out.println("准备处理消息 : " + msg);
        try {
            Thread.sleep(5000);  //5秒处理一个
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

转载于:https://my.oschina.net/thinwonton/blog/997679

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值