ActiveMQ 到底是推还是拉?
http://activemq.apache.org/destination-options.html
1. consumer 的配置参数如下图:

配置consumer的示例:
public void run() {
    try {
        // Create a ConnectionFactory
        ActiveMQConnectionFactory connectionFactory =
                new ActiveMQConnectionFactory("tcp://localhost:61616");
        // Create a Connection
        Connection connection = connectionFactory.createConnection();
        connection.start();
        connection.setExceptionListener(this);
        // Create a Session
        ActiveMQSession session = 
          (ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        // Create the destination (Topic or Queue)
        // 此时加入参数
        ActiveMQQueue destination = 
          (ActiveMQQueue) session.createQueue("TEST.FOO?consumer.prefetchSize=10");
        // Create a MessageConsumer from the Session to the Topic or Queue
        ActiveMQMessageConsumer consumer = 
          (ActiveMQMessageConsumer) session.createConsumer(destination);
        // 打印出prefetchSize参数值
        System.out.println("prefetchSize=" + consumer.getPrefetchNumber());
        // Wait for a message
        Message message = consumer.receive();
        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            String text = textMessage.getText();
            System.out.println("Received: " + text);
        } else {
            System.out.println("Received: " + message);
        }
        consumer.close();
        session.close();
        connection.close();
    } catch (Exception e) {
        System.out.println("Caught: " + e);
        e.printStackTrace();
    }
}
在创建Queue的时候,配置以url形式跟在队列名后面:session.createQueue("TEST.FOO?consumer.prefetchSize=10")
consumer的prefetchSize参数默认为1000。
consumer 有推和拉2种方式获取消息:当 prefetchSize = 0 时,pull;当 prefetchSize > 0 时,push。
2. broker分发消息的逻辑在org.apache.activemq.broker.region.Queue.doActualDispatch方法中:
private PendingList doActualDispatch(PendingList list) throws Exception {
    List<Subscription> consumers;
    consumersLock.writeLock().lock();
    try {
        if (this.consumers.isEmpty()) {
            // slave dispatch happens in processDispatchNotification
            return list;
        }
        consumers = new ArrayList<Subscription>(this.consumers);
    } finally {
        consumersLock.writeLock().unlock();
    }
    Set<Subscription> fullConsumers = new HashSet<Subscription>(this.consumers.size());
    for (Iterator<MessageReference> iterator = list.iterator(); iterator.hasNext();) {
        MessageReference node = iterator.next();
        Subscription target = null;
        for (Subscription s : consumers) {
            if (s instanceof QueueBrowserSubscription) {
                continue;
            }
            if (!fullConsumers.contains(s)) {
                if (!s.isFull()) {
                    if (dispatchSelector.canSelect(s, node) && assignMessageGroup(s, (QueueMessageReference)node) && !((QueueMessageReference) node).isAcked() ) {
                        // Dispatch it.
                        s.add(node);
                        LOG.trace("assigned {} to consumer {}", node.getMessageId(), s.getConsumerInfo().getConsumerId());
                        iterator.remove();
                        target = s;
                        break;
                    }
                } else {
                    // no further dispatch of list to a full consumer to
                    // avoid out of order message receipt
                    fullConsumers.add(s);
                    LOG.trace("Subscription full {}", s);
                }
            }
        }
        if (target == null && node.isDropped()) {
            iterator.remove();
        }
        // return if there are no consumers or all consumers are full
        if (target == null && consumers.size() == fullConsumers.size()) {
            return list;
        }
        // If it got dispatched, rotate the consumer list to get round robin
        // distribution.
        if (target != null && !strictOrderDispatch && consumers.size() > 1
                && !dispatchSelector.isExclusiveConsumer(target)) {
            consumersLock.writeLock().lock();
            try {
                if (removeFromConsumerList(target)) {
                    addToConsumerList(target);
                    consumers = new ArrayList<Subscription>(this.consumers);
                }
            } finally {
                consumersLock.writeLock().unlock();
            }
        }
    }
    return list;
}
2层for循环,外面是消息,里面是consumer,只要consumer没有饱和,broker一直会给consumer分发消息。
对于一个consumer而言,未确认的消息数大于等于prefetchSize,则认为该consumer是饱的
// PrefetchSubscription
public boolean isFull() {
// 未确认的消息数 = 已发送给该consumer的消息数 - 收到确认的消息数
return dispatched.size() - prefetchExtension.get() >= info.getPrefetchSize();
}
因为 consumer 的 prefetchSize 参数默认为1000,所以 activeMQ 默认是推。而且是一条一条地推。
3. consumer获取消息有同步和异步两种方式:consumer.receive() 或 consumer.setMessageListener(listener)
对于 receive 方式,如果prefetchSize = 0 并且本地没有缓存消息,则发送一个pull 命令给broker;
否则,则从本地缓存中取消息。
// ActiveMQMessageConsumer
public Message receive() throws JMSException {
checkClosed();
checkMessageListener(); sendPullCommand(0);
MessageDispatch md = dequeue(-1);
if (md == null) {
return null;
} beforeMessageIsConsumed(md);
afterMessageIsConsumed(md, false); return createActiveMQMessage(md);
} protected void sendPullCommand(long timeout) throws JMSException {
clearDeliveredList();
if (info.getCurrentPrefetchSize() == 0 && unconsumedMessages.isEmpty()) {
MessagePull messagePull = new MessagePull();
messagePull.configure(info);
messagePull.setTimeout(timeout);
session.asyncSendPacket(messagePull);
}
}
consumer 本地消息缓存在
// These are the messages waiting to be delivered to the client
protected final MessageDispatchChannel unconsumedMessages;
消息进入缓存有2条路线,调用栈分别如下:
(1)

(2)

consumer.setMessageListener 异步获取消息的调用栈如下:

ActiveMQ 到底是推还是拉?的更多相关文章
- kafka的推和拉的问题
		
之前学习过这一问题,但是面试又被问道了.再次记录下 推还是拉? Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers将消息推送到consumer,也就是pull还p ...
 - ERP 推式  拉式  工序拉式   装配拉式   倒冲
		
ERP 推式 拉式 工序拉式 装配拉式 倒冲 以上為生产订单(wip)中的原料供应方式,最常用的有Pull和Push. PULL即拉动方式: 拉式生产是生产为主,原材料是由专门的配送人员按 ...
 - 揭密: M2和高房价到底谁推高了谁?
		
近期,著名经济学家吴敬链向新华网等媒体表示:房价高的根本原本就是货币超发.近期十年来我国M2增长率(广义货币增长率)太快."钱太多了,有些人要保值就要投资买房,又因货币非常多购买力非常强.就 ...
 - Message Queue中的推与拉(转)
		
Message Queue的设计和实现(7)http://mp.weixin.qq.com/s/zQdDBAHu1UgJJzxH2eCHgQ 数据发送中的推与拉. 当MQ要把数据给消费者的时候,就涉及 ...
 - git push & git pull 推送/拉取分支
		
git push与git pull是一对推送/拉取分支的git命令. git push 使用本地的对应分支来更新对应的远程分支. $ git push <远程主机名> <本地分支名& ...
 - POJ 2478 线性递推欧拉函数
		
题意: 求sigma phi(n) 思路: 线性递推欧拉函数 (维护前缀和) //By SiriusRen #include <cstdio> using namespace std; # ...
 - Linux架构--------Rsync守护进程推和拉
		
一.Rsync基本概述 rsync是一款开源.快速.多功能.可实现全量及增量的本地或远程数据同步备份的优秀工具.rsync软件适用于Unix/linux/Windows等多种操作系统平台. 二.Rsy ...
 - Linux架构之Rsync守护进程推和拉
		
第三十三章 Rsync服务 33.1)Rsync基本概述 rsync是一款开源.快速.多功能.可实现全量及增量的本地或远程数据同步备份的优秀工具.rsync软件适用于Unix/linux/Window ...
 - QQ好友状态,QQ群友状态,究竟是推还是拉? 网页端收消息,究竟是推还是拉?
		
https://mp.weixin.qq.com/s/KB1zdKcsh4PXXuJh4xb_Zw 网页端收消息,究竟是推还是拉? 原创 58沈剑 架构师之路 2020-12-28 https:/ ...
 
随机推荐
- hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥
			
Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Pr ...
 - SpringBoot学习路线
			
网上也有很多github资源,都是自己学习Spring Boot时候,自己练的代码 虽然现在最新的版本用2.1.3.RELEASE版本,以前版本的demo运行可能会遇到错误.但是有总比没有要好,不是么 ...
 - StringBuffer 清空StringBuffer的实例的三种方法
			
@Test public void testStringbuffer(){ //StringBuffer类没有clear方法,不过可以通过下面两种方法来清空一个StringBuffer的实例: Str ...
 - 从DFS到记忆化DFS到动态规划
			
什么是动态规划? 动态规划(Dynamic Programming)是通过组合子问题的解来解决问题的.动态规划是用于求解包含重叠子问题的最优化问题的方法.其基本思想是,将原问题分解为相似的子问题.在求 ...
 - bitbucket工程改名导致 repository does not exist. fatal: Could not read from remote repository.
			
在bitbucket上把工程改名了,就忘了. 结果同步时报错. 先在本地查看一下 git remote -v 果然是工程的老名字 origin git@bitbucket.org:XXX/oldnam ...
 - Tomcat部署项目定时任务跑了两次
			
在server.xml下面找到Host这行代码 <Host name="localhost" appBase="webapps" unpackWARs=& ...
 - ftp服务器搭建(离线安装vsftpd),配置
			
1.下载vsftp:http://rpmfind.net/linux/rpm2html/search.php?query=vsftpd(x86-64) 2.检查是否已经安装了vsftp rpm -qa ...
 - Oracle中判断(case when),截取(substr),位置(instr)用法
			
转自:http://rainbowdesert.iteye.com/blog/1677911 博客分类: SQL 1. 判断(case when) SELECT col1, col2, CASE ...
 - Unity Shader入门精要之 screen post-processing effect
			
本篇记录了学习Unity Shader入门精要的屏幕后处理的一些知识点. OnRenderImage(RenderTexture src, RenderTexture dest) 以上函数是Unity ...
 - ThinkPHP表单自动验证(注册功能)
			
控制器中: 模型中: 视图中: