ActiveMQ queue 分页
分页:即获取部分数据,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 分页的更多相关文章
- ActiveMQ Queue vs Topic vs VirtualTopic
之前写过一篇文章讨论VirtualTopic,但觉得不够透彻,这里再根据实验结果进行一次横向对比破除模糊和选择困难症. 文章中核心对比要素是:消息副本和负载均衡 Queue的特点和优势 ActiveM ...
- ActiveMQ queue和topic,持久订阅和非持久订阅
消息的 destination 分为 queue 和 topic,而消费者称为 subscriber(订阅者).queue 中的消息只会发送给一个订阅者,而 topic 的消息,会发送给每一个订阅者. ...
- ActiveMQ queue 代码示例
生产者: package com.111.activemq; import javax.jms.Connection; import javax.jms.ConnectionFactory; impo ...
- ActiveMQ Queue示例
一.Queue 发送 public class JmsSend { public static void main(String[] args) throws JMSException { Conne ...
- spring整合activemq发送MQ消息[queue模式]实例
queue类型消息 pom依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</ ...
- Spring整合ActiveMQ及多个Queue消息监听的配置
消息队列(MQ)越来越火,在java开发的项目也属于比较常见的技术,MQ的相关使用也成java开发人员必备的技能.笔者公司采用的MQ是ActiveMQ,且消息都是用的点对点的模式.本文记录了实 ...
- ActiveMQ发消息和收消息
来自:http://blog.163.com/chengwei_1104/blog/static/53645274201382315625329/ ActiveMQ 是Apache出品,最流行的,能力 ...
- ActiveMQ, RabbitMQ和ZeroMQ 选型关注点
选择MQ时,主要关注的特性,可能就以下几个: 通信模式(是否满足业务场景): ActiveMQ: queue(producer/consumer), topic(publisher/subsriber ...
- ActiveMQ:使用Python访问ActiveMQ
Windows 10家庭中文版,Python 3.6.4,stomp.py 4.1.21 ActiveMQ支持Python访问,提供了基于STOMP协议(端口为61613)的库. ActiveMQ的官 ...
随机推荐
- Broken Keyboard (a.k.a. Beiju Text) 思路
问题:You’re typing a long text with a broken keyboard. Well it’s not so badly broken. The only problem ...
- _map
地图属性控制表 comment 备注 Map 地图ID,.gps第一个参数 Zone 区域ID,.gps第二个参数,整个地图时填0 Area 地域ID,.gps第三个参数,整个地图或区域时填0 Cha ...
- codeforces 768D Jon and Orbs
题目链接:http://codeforces.com/problemset/problem/768/D 令$f[i][j]$表示当前产生过了$i$个球,产生过了$j$个不同的球的概率. ${Ans_i ...
- CentOS7下搭建LAMP+FreeRadius+Daloradius Web管理
注意:本文所有命令均在root命令下执行. freeradius服务官网:http://freeradius.org/ daloradius Web管理页面官网:https://sourceforge ...
- Linux简单入门
1.目录切换命令 cd usr 切换到该目录下usr目录 cd ../ 切换到上一层目录 cd / 切换到系统根目录 cd ~ 切换到用户主目录 cd - 切换到上一个所在目录 2.目录的操作命令 1 ...
- leecode第四题(寻找两个有序数组的中位数)
题解: class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<i ...
- Python Scrapy 爬虫框架实例(一)
之前有介绍 scrapy 的相关知识,但是没有介绍相关实例,在这里做个小例,供大家参考学习. 注:后续不强调python 版本,默认即为python3.x. 爬取目标 这里简单找一个图片网站,获取图片 ...
- arcgis 浅入
首先声明,此文只是用于学习,非商业用途!!20181226谷子弟留 有朋友需要用arcgis来学习分析图块,实现图块的分类和数据分析和统计. 于是网上找了找资源. http://pan.baidu ...
- tchart5
https://blog.csdn.net/wuyuanjingni/article/details/8585810
- 雷林鹏分享: C# 教程
C# 教程 C# 是一个简单的.现代的.通用的.面向对象的编程语言,它是由微软(Microsoft)开发的. 本教程将告诉您基础的 C# 编程,同时将向您讲解 C# 编程语言相关的各种先进理念. 现在 ...