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 到底是推还是拉?的更多相关文章

  1. kafka的推和拉的问题

    之前学习过这一问题,但是面试又被问道了.再次记录下 推还是拉? Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers将消息推送到consumer,也就是pull还p ...

  2. ERP 推式 拉式 工序拉式 装配拉式 倒冲

    ERP 推式  拉式  工序拉式   装配拉式   倒冲 以上為生产订单(wip)中的原料供应方式,最常用的有Pull和Push. PULL即拉动方式: 拉式生产是生产为主,原材料是由专门的配送人员按 ...

  3. 揭密: M2和高房价到底谁推高了谁?

    近期,著名经济学家吴敬链向新华网等媒体表示:房价高的根本原本就是货币超发.近期十年来我国M2增长率(广义货币增长率)太快."钱太多了,有些人要保值就要投资买房,又因货币非常多购买力非常强.就 ...

  4. Message Queue中的推与拉(转)

    Message Queue的设计和实现(7)http://mp.weixin.qq.com/s/zQdDBAHu1UgJJzxH2eCHgQ 数据发送中的推与拉. 当MQ要把数据给消费者的时候,就涉及 ...

  5. git push & git pull 推送/拉取分支

    git push与git pull是一对推送/拉取分支的git命令. git push 使用本地的对应分支来更新对应的远程分支. $ git push <远程主机名> <本地分支名& ...

  6. POJ 2478 线性递推欧拉函数

    题意: 求sigma phi(n) 思路: 线性递推欧拉函数 (维护前缀和) //By SiriusRen #include <cstdio> using namespace std; # ...

  7. Linux架构--------Rsync守护进程推和拉

    一.Rsync基本概述 rsync是一款开源.快速.多功能.可实现全量及增量的本地或远程数据同步备份的优秀工具.rsync软件适用于Unix/linux/Windows等多种操作系统平台. 二.Rsy ...

  8. Linux架构之Rsync守护进程推和拉

    第三十三章 Rsync服务 33.1)Rsync基本概述 rsync是一款开源.快速.多功能.可实现全量及增量的本地或远程数据同步备份的优秀工具.rsync软件适用于Unix/linux/Window ...

  9. QQ好友状态,QQ群友状态,究竟是推还是拉? 网页端收消息,究竟是推还是拉?

    https://mp.weixin.qq.com/s/KB1zdKcsh4PXXuJh4xb_Zw 网页端收消息,究竟是推还是拉? 原创 58沈剑 架构师之路 2020-12-28   https:/ ...

随机推荐

  1. tomcat中实现特定路径下的图片的url访问Tomcat配置图片保存路径,图片不保存在项目路径下

    使用Tomcat作为服务器的时候,如果不配置图片保存路径,将图片保存在项目路径下,那么再次打war包发布项目可能会造成图片的丢失,每次重启前将图片先保存再copy到服务器明显不方便,这时可以配置图片保 ...

  2. ngui 适配iphone x

    using UnityEngine; using System.Collections; [RequireComponent(typeof(UIPanel))]public class FixedUI ...

  3. Python安装常见问题:ModuleNotFoundError: No module named '_ctypes' 解决办法

    一般位于3.7以上版本编译安装时出错 缺少依赖包libffi-devel 在安装3.7以上版本时,需要一个新的libffi-devel包做依赖 解决方法: yum install libffi-dev ...

  4. VMware网络连接模式—桥接、NAT以及仅主机模式的详细介绍和区别

    在使用VMware Workstation(以下简称:VMware)创建虚拟机的过程中,配置虚拟机的网络连接是非常重要的一环,当我们为虚拟机配置网络连接时,我们可以看到如下图所示的几种网络连接模式:桥 ...

  5. C语言之网络编程(服务器和客户端)

    Linux网络编程 1. 套接字:源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字.其用于标识客户端请求的服务器和服务. 常用的TCP/IP协议的3种套接字类型如下所示. (1)流套接 ...

  6. 学习笔记6—pandas中ix,loc,iloc有什么区别?

    直接看例子: >>> data = pd.Series(np.arange(10), index=[49,48,47,46,45, 1, 2, 3, 4, 5]) >>& ...

  7. BootStrap table隐藏列两种方式 (踩坑)

    1.第一种  利用 visible 属性 { field : 'userAccount', title : '订阅人', visible : visible(), formatter:function ...

  8. iframe和ajax文件上传方法

    为什么使用这两种方法文件上传呢,主要是因为局部刷新问题 上传问题,主要是使用form表单,或者用请求一个文件上传 iframe 大多网站都是有一个整体的固定结构,然后进行局部刷新,我们可以使用AJAX ...

  9. legend2---开发日志2(注释和函数比较好的写法)

    legend2---开发日志2(注释和函数比较好的写法) 一.总结 一句话总结: 函数用_接意群 注释的关键字用[]括起来 注释的步骤用中文的步骤二字 1.为何以步骤为名写注释? 结构非常清晰 //步 ...

  10. (9)进程---JoinableQueue队列

    消费者模型-->存和取得过程 和Queue队列区别:解决了Queue队列拿取完,程序阻塞不能自动关闭(依靠放入None来解决)的问题--->参见上个例子 put 存入, get 获取 q. ...