分页:即获取部分数据,queue按页从message cursor读取消息,然后分发给consumer。

页大小:

public abstract class BaseDestination implements Destination {
/**
* The maximum number of messages to page in to the destination from
* persistent storage
*/
public static final int MAX_PAGE_SIZE = 200;
}

存放分页消息的数据结构:

public class Queue extends BaseDestination implements Task, UsageListener {
// message cursor,可视为消息的数据源
protected PendingMessageCursor messages;
// 所有的分页消息
private final PendingList pagedInMessages = new OrderedPendingList();
// 剩余的没有dispatch的分页消息
protected PendingList pagedInPendingDispatch = new OrderedPendingList();
}

把消息添加到分页中:

protected void pageInMessages(boolean force) throws Exception {
doDispatch(doPageInForDispatch(force, true));
}
 private PendingList doPageInForDispatch(boolean force, boolean processExpired) throws Exception {
List<QueueMessageReference> result = null;
PendingList resultList = null; // 根据maxPageSize和message cursor中的大小,决定需要读取的消息数量
int toPageIn = Math.min(getMaxPageSize(), messages.size());
int pagedInPendingSize = 0;
pagedInPendingDispatchLock.readLock().lock();
try {
pagedInPendingSize = pagedInPendingDispatch.size();
} finally {
pagedInPendingDispatchLock.readLock().unlock();
} LOG.debug("{} toPageIn: {}, Inflight: {}, pagedInMessages.size {}, pagedInPendingDispatch.size {}, enqueueCount: {}, dequeueCount: {}, memUsage:{}",
new Object[]{
destination.getPhysicalName(),
toPageIn,
destinationStatistics.getInflight().getCount(),
pagedInMessages.size(),
pagedInPendingSize,
destinationStatistics.getEnqueues().getCount(),
destinationStatistics.getDequeues().getCount(),
getMemoryUsage().getUsage()
});
if (isLazyDispatch() && !force) {
// Only page in the minimum number of messages which can be
// dispatched immediately.
toPageIn = Math.min(getConsumerMessageCountBeforeFull(), toPageIn);
}
if (toPageIn > 0 && (force || (!consumers.isEmpty() && pagedInPendingSize < getMaxPageSize()))) {
int count = 0;
result = new ArrayList<QueueMessageReference>(toPageIn);
messagesLock.writeLock().lock();
try {
try {
messages.setMaxBatchSize(toPageIn);
messages.reset();
while (messages.hasNext() && count < toPageIn) {
MessageReference node = messages.next();
messages.remove(); QueueMessageReference ref = createMessageReference(node.getMessage());
if (processExpired && ref.isExpired()) {
if (broker.isExpired(ref)) {
messageExpired(createConnectionContext(), ref);
} else {
ref.decrementReferenceCount();
}
} else {
// 添加QueueMessageReference到result中
result.add(ref);
count++;
}
}
} finally {
messages.release();
}
} finally {
messagesLock.writeLock().unlock();
}
// Only add new messages, not already pagedIn to avoid multiple
// dispatch attempts
pagedInMessagesLock.writeLock().lock();
try {
if(isPrioritizedMessages()) {
resultList = new PrioritizedPendingList();
} else {
resultList = new OrderedPendingList();
}
for (QueueMessageReference ref : result) {
if (!pagedInMessages.contains(ref)) {
//分别添加QueueMessageReference到 pagedInMessages 和 resultList
//resultList作为返回值,直接传递给doDispatch(PendingList list),
//在doDispatch中,分发给消费者后,就会从 resultList 中删除,
pagedInMessages.addMessageLast(ref);
resultList.addMessageLast(ref);
} else {
ref.decrementReferenceCount();
// store should have trapped duplicate in it's index, also cursor audit
// we need to remove the duplicate from the store in the knowledge that the original message may be inflight
// note: jdbc store will not trap unacked messages as a duplicate b/c it gives each message a unique sequence id
LOG.warn("{}, duplicate message {} paged in, is cursor audit disabled? Removing from store and redirecting to dlq", this, ref.getMessage());
if (store != null) {
ConnectionContext connectionContext = createConnectionContext();
store.removeMessage(connectionContext, new MessageAck(ref.getMessage(), MessageAck.POSION_ACK_TYPE, 1));
broker.getRoot().sendToDeadLetterQueue(connectionContext, ref.getMessage(), null, new Throwable("duplicate paged in from store for " + destination));
}
}
}
} finally {
pagedInMessagesLock.writeLock().unlock();
}
} else {
// Avoid return null list, if condition is not validated
resultList = new OrderedPendingList();
} return resultList;
} //分发消息
private void doDispatch(PendingList list) throws Exception {
boolean doWakeUp = false; pagedInPendingDispatchLock.writeLock().lock();
try {
//存在需要重新发送的消息
if (!redeliveredWaitingDispatch.isEmpty()) {
// Try first to dispatch redelivered messages to keep an
// proper order
redeliveredWaitingDispatch = doActualDispatch(redeliveredWaitingDispatch);
}
//存在没有分发的分页消息
if (!pagedInPendingDispatch.isEmpty()) {
// Next dispatch anything that had not been
// dispatched before.
pagedInPendingDispatch = doActualDispatch(pagedInPendingDispatch);
}
// and now see if we can dispatch the new stuff.. and append to
// the pending
// list anything that does not actually get dispatched.
if (list != null && !list.isEmpty()) {
if (pagedInPendingDispatch.isEmpty()) {
//doActualDispatch进行实际的分发消息:
//分发给消费者的消息,会从list中删除,list中保存剩下的消息,doActualDispatch返回list
pagedInPendingDispatch.addAll(doActualDispatch(list));
} else {
for (MessageReference qmr : list) {
if (!pagedInPendingDispatch.contains(qmr)) {
pagedInPendingDispatch.addMessageLast(qmr);
}
}
doWakeUp = true;
}
}
} finally {
pagedInPendingDispatchLock.writeLock().unlock();
} if (doWakeUp) {
// avoid lock order contention
asyncWakeup();
}
} // 实际分发消息
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());
//从list中删除
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;
}

ActiveMQ queue 分页的更多相关文章

  1. ActiveMQ Queue vs Topic vs VirtualTopic

    之前写过一篇文章讨论VirtualTopic,但觉得不够透彻,这里再根据实验结果进行一次横向对比破除模糊和选择困难症. 文章中核心对比要素是:消息副本和负载均衡 Queue的特点和优势 ActiveM ...

  2. ActiveMQ queue和topic,持久订阅和非持久订阅

    消息的 destination 分为 queue 和 topic,而消费者称为 subscriber(订阅者).queue 中的消息只会发送给一个订阅者,而 topic 的消息,会发送给每一个订阅者. ...

  3. ActiveMQ queue 代码示例

    生产者: package com.111.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; impo ...

  4. ActiveMQ Queue示例

    一.Queue 发送 public class JmsSend { public static void main(String[] args) throws JMSException { Conne ...

  5. spring整合activemq发送MQ消息[queue模式]实例

    queue类型消息 pom依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</ ...

  6. Spring整合ActiveMQ及多个Queue消息监听的配置

        消息队列(MQ)越来越火,在java开发的项目也属于比较常见的技术,MQ的相关使用也成java开发人员必备的技能.笔者公司采用的MQ是ActiveMQ,且消息都是用的点对点的模式.本文记录了实 ...

  7. ActiveMQ发消息和收消息

    来自:http://blog.163.com/chengwei_1104/blog/static/53645274201382315625329/ ActiveMQ 是Apache出品,最流行的,能力 ...

  8. ActiveMQ, RabbitMQ和ZeroMQ 选型关注点

    选择MQ时,主要关注的特性,可能就以下几个: 通信模式(是否满足业务场景): ActiveMQ: queue(producer/consumer), topic(publisher/subsriber ...

  9. ActiveMQ:使用Python访问ActiveMQ

    Windows 10家庭中文版,Python 3.6.4,stomp.py 4.1.21 ActiveMQ支持Python访问,提供了基于STOMP协议(端口为61613)的库. ActiveMQ的官 ...

随机推荐

  1. IIS客户端没有权限

    运行CMDicacls c:\ /setintegritylevel M

  2. React Native原生模块向JS传递数据的几种方式(Android)

    一般情况可以分为三种方式: 1. 通过回调函数Callbacks的方式 2. 通过Promises的异步的方式 3. 通过发送事件的事件监听的方式. 参考文档:传送门

  3. Codeforces 510 E. Fox And Dinner

    题目链接:http://codeforces.com/problemset/problem/510/E 乍一看和那啥魔术球问题有点神似啊/XD 其实是不一样的. 解决这道问题的关键在于发现若是相邻的两 ...

  4. P3146 [USACO16OPEN]248 & P3147 [USACO16OPEN]262144

    注:两道题目题意是一样的,但是数据范围不同,一个为弱化版,另一个为强化版. P3146传送门(弱化版) 思路: 区间动规,设 f [ i ][ j ] 表示在区间 i ~ j 中获得的最大值,与普通区 ...

  5. Centos7 linux下通过源码安装redis以及使用

    下载redis安装包 wget http://download.redis.io/releases/redis-5.0.3.tar.gz 解压压缩包 tar -zxvf redis-.tar.gz y ...

  6. 本地Windows上安装 MySQL数据库

    1.首先下载mysql安装文件,下载地址:https://dev.mysql.com/downloads/mysql/ 2.将下载下来的压缩包解压到本地一个文件夹中 3.在文件根目录下新增my.ini ...

  7. 学习笔记57—归一化 (Normalization)、标准化 (Standardization)和中心化/零均值化 (Zero-centered)

    1 概念   归一化:1)把数据变成(0,1)或者(1,1)之间的小数.主要是为了数据处理方便提出来的,把数据映射到0-1范围之内处理,更加便捷快速.2)把有量纲表达式变成无量纲表达式,便于不同单位或 ...

  8. 关于table动态添加数据 单元格合并 数组合并

    var newArr = [ {"BranchID":1,"BranchName":"城二","BranchFullName&qu ...

  9. ThinkPHP的数据操作

    查询: 具体数据的操作方法使用: 1. where()条件     $model->where(条件值);  //条件值就是sql语句where后边的结果值 2. limit() 限制条数  $ ...

  10. spring ----> ResourceBundle [message] not found for MessageSource: Can't find bundle for base name message, local_zh

    环境: idea 2018.1.3社区版,jdk8,spring4.2.0,maven3.5.2 主题: spring国际化 出现的问题: ResourceBundle [message] not f ...