分页:即获取部分数据,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. C# winform窗体间传值(使用委托或事件)

    窗体间传值 今天得空,刚好看到网上好多人再找winform窗体间传值的问题,由于昨天项目的优化的感觉不错,就写了个C# winform窗体间传值的demo,希望能给需要的人的带来帮助: 工程的源代码地 ...

  2. React native 开发如何使用阿里的icon

    首先是通过Text来引用的 但是区分是 familay <Text style={{fontFamily:'iconfont', fontSize:fontsize, color:this.st ...

  3. Selenium IDE使用

    基于版本Selenium IDE 3.2.2(注:该工具不常用,可以使用定位元素是否存在) Selenium IDE可以录制也很方便,当然录下来的经常回放不成功,需要自己调试就是了.它是只针对Web页 ...

  4. 3. 使用vue-cli创建项目

    eslint: 用来做项目编码规范检查的工具基本原理: 定义了很多规则, 检查项目的代码一旦发现违背了某个规则就输出相应的提示信息有相应的配置, 可定制检查 1. 创建项目 vue脚手架(vue-cl ...

  5. ip啊

    网络模型被OSI分成七层,TCP/IP协议大致对应了2.3.4.7层,分别是数据链路层.网络层.传输层.应用层,IP协议处于网络层上,它的工作原理说白了并不复杂: 整个互联网上所有的机器都有唯一一个I ...

  6. cookie的常用操作

    cookie介绍: 1. cookie的简单介绍就是把用户的登录信息缓存在本机的浏览器中,且最大容量为4KB, 2. 这种存储是不安全的,通常一般会进行加密处理,但是依旧不能做到安全,所以一般要优先考 ...

  7. Rancher中的服务升级实验

    个容器副本,使用nginx:1.13.0镜像.假设使用一段时期以后,nginx的版本升级到1.13.1了,如何将该服务的镜像版本升级到新的版本?实验步骤及截图如下: 步骤截图: 个容器,选择镜像ngi ...

  8. linux基础05-管道及IO重定向

    (1)I/O重定向:Linux:>: 覆盖输出>>:追加输出 (2)set -C: 禁止对已经存在文件使用覆盖重定向: 强制覆盖输出,则使用 >|set +C: 关闭上述功能 ...

  9. 全栈性能测试修炼宝典--Jmeter实战(一)

    性能测试方向职业发展 1.软件测试发展路线 我们可以暂且把软件测试职业路线分为3个方向,分别是业务路线.技术路线.管理路线:4个象限,分别为执行层.中层.中高层过渡.高层. (1)业务路线 常见业务路 ...

  10. 数据结构(C语言版)-第2章 线性表

    #define MAXSIZE 100 //最大长度 typedef struct { ElemType *elem; //指向数据元素的基地址 int length; //线性表的当前长度 }SqL ...