http://activemq.apache.org/my-producer-blocks.html 回答了这个问题:

ActiveMQ 5.x 支持Message Cursors,它默认把消息从内存移出到磁盘上。所以,只有在分配给message store的磁盘空间被用完了,才会出现问题。分配的磁盘空间是可以配置的。

http://activemq.apache.org/message-cursors.html 有一张描述store based cursor的图:

上图中的元素对应的数据结构如下:

public class Queue extends BaseDestination implements Task, UsageListener {
// StoreQueueCursor
protected PendingMessageCursor messages;
}
public class StoreQueueCursor extends AbstractPendingMessageCursor {

    private static final Logger LOG = LoggerFactory.getLogger(StoreQueueCursor.class);
private final Broker broker;
private int pendingCount;
private final Queue queue;
// 非持久化 pending cursor,真实类型是 FilePendingMessageCursor
private PendingMessageCursor nonPersistent;
// 持久化 pending cursor,真实类型是 QueueStorePrefetch
private final QueueStorePrefetch persistent;
private boolean started;
private PendingMessageCursor currentCursor;
}
class QueueStorePrefetch extends AbstractStoreCursor {
private static final Logger LOG = LoggerFactory.getLogger(QueueStorePrefetch.class);
// Message Store
private final MessageStore store;
private final Broker broker;
}

调试时,message store 的类型为 KahaDBTransactionStore$1

producer发送消息后,broker的调用栈:

org.apache.activemq.broker.region.Queue.doMessageSend

void doMessageSend(final ProducerBrokerExchange producerExchange, final Message message) throws IOException,
Exception {
final ConnectionContext context = producerExchange.getConnectionContext();
ListenableFuture<Object> result = null;
boolean needsOrderingWithTransactions = context.isInTransaction(); producerExchange.incrementSend();
checkUsage(context, producerExchange, message);
sendLock.lockInterruptibly();
try {
// store类型是KahaDBTransactionStore$1
// 持久化消息,先存入kahadb,也就是图中的message store
if (store != null && message.isPersistent()) {
try {
message.getMessageId().setBrokerSequenceId(getDestinationSequenceId());
if (messages.isCacheEnabled()) {
result = store.asyncAddQueueMessage(context, message, isOptimizeStorage());
result.addListener(new PendingMarshalUsageTracker(message));
} else {
store.addMessage(context, message);
}
if (isReduceMemoryFootprint()) {
message.clearMarshalledState();
}
} catch (Exception e) {
// we may have a store in inconsistent state, so reset the cursor
// before restarting normal broker operations
resetNeeded = true;
throw e;
}
}
// did a transaction commit beat us to the index?
synchronized (orderIndexUpdates) {
needsOrderingWithTransactions |= !orderIndexUpdates.isEmpty();
}
if (needsOrderingWithTransactions ) {
// If this is a transacted message.. increase the usage now so that
// a big TX does not blow up
// our memory. This increment is decremented once the tx finishes..
message.incrementReferenceCount(); registerSendSync(message, context);
} else { // 普通的非事务消息,加到 pending list 中
// Add to the pending list, this takes care of incrementing the
// usage manager.
sendMessage(message);
}
} finally {
sendLock.unlock();
}
if (!needsOrderingWithTransactions) {
messageSent(context, message);
}
if (result != null && message.isResponseRequired() && !result.isCancelled()) {
try {
result.get();
} catch (CancellationException e) {
// ignore - the task has been cancelled if the message
// has already been deleted
}
}
}

StoreQueueCursor.addMessageLast

public synchronized void addMessageLast(MessageReference node) throws Exception {
if (node != null) {
Message msg = node.getMessage();
if (started) {
pendingCount++;
if (!msg.isPersistent()) {
//对应图中的 non-persistent pending cursor
nonPersistent.addMessageLast(node);
}
}
if (msg.isPersistent()) {
// 对应图中的 persistent pending cursor
persistent.addMessageLast(node);
}
}
}

store based cursor图中的数据流,基本梳理清楚,还差non-persistent pending curosr 到 tmeporary files的数据流。

//org.apache.activemq.broker.region.cursors.FilePendingMessageCursor
@Override
public synchronized void addMessageLast(MessageReference node) throws Exception {
tryAddMessageLast(node, 0);
} @Override
public synchronized boolean tryAddMessageLast(MessageReference node, long maxWaitTime) throws Exception {
if (!node.isExpired()) {
try {
regionDestination = (Destination) node.getMessage().getRegionDestination();
if (isDiskListEmpty()) {
if (hasSpace() || this.store == null) {
memoryList.addMessageLast(node);
node.incrementReferenceCount();
setCacheEnabled(true);
return true;
}
}
if (!hasSpace()) {
if (isDiskListEmpty()) {
expireOldMessages();
if (hasSpace()) {
memoryList.addMessageLast(node);
node.incrementReferenceCount();
return true;
} else {
flushToDisk();
}
}
}
if (systemUsage.getTempUsage().waitForSpace(maxWaitTime)) {
ByteSequence bs = getByteSequence(node.getMessage());
//把消息写到磁盘
getDiskList().addLast(node.getMessageId().toString(), bs);
return true;
}
return false; } catch (Exception e) {
LOG.error("Caught an Exception adding a message: {} first to FilePendingMessageCursor ", node, e);
throw new RuntimeException(e);
}
} else {
discardExpiredMessage(node);
}
//message expired
return true;
} //org.apache.activemq.broker.region.cursors.AbstractPendingMessageCursor
// 判断内存使用量是否超过70%
public boolean hasSpace() {
return systemUsage != null ? (!systemUsage.getMemoryUsage().isFull(memoryUsageHighWaterMark)) : true;
}

在内存使用发送变化时,会触发flush:

FilePendingMessageCursor.onUsageChanged(Usage usage, int oldPercentUsage, int newPercentUsage)

public void onUsageChanged(Usage usage, int oldPercentUsage, int newPercentUsage) {
// 内存使用超过70%,会把消息刷到磁盘上,后面的hasSpace()方法也是以此判断
if (newPercentUsage >= getMemoryUsageHighWaterMark()) {
synchronized (this) {
if (!flushRequired && size() != 0) {
flushRequired =true;
if (!iterating) {
expireOldMessages();
if (!hasSpace()) {
flushToDisk();
flushRequired = false;
}
}
}
}
}
}
public abstract class AbstractPendingMessageCursor implements PendingMessageCursor {
protected int memoryUsageHighWaterMark = 70;
}

ActiveMQ producer不断发送消息,会导致broker内存耗尽吗?的更多相关文章

  1. kafka producer batch 发送消息

    1. 使用 KafkaProducer 发送消息,是按 batch 发送的,producer 首先把消息放入 ProducerBatch 中: org.apache.kafka.clients.pro ...

  2. producer怎样发送消息到指定的partitions

    http://www.aboutyun.com/thread-9906-1-1.html http://my.oschina.net/u/591402/blog/152837 https://gith ...

  3. ActiveMQ producer 提交事务时突然宕机,会发生什么

    producer 在提交事务时,发生宕机,commit 的命令没有发送到 broker,这时会发生什么? ActiveMQ 开启事务发送消息的步骤: session.getTransactionCon ...

  4. 17 个方面,综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列

    原文:https://mp.weixin.qq.com/s/lpsQ3dEZHma9H0V_mcxuTw 一.资料文档 二.开发语言 三.支持的协议 四.消息存储 五.消息事务 六.负载均衡 七.集群 ...

  5. 综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列

    来源:http://t.cn/RVDWcfe 一.资料文档 Kafka:中.有kafka作者自己写的书,网上资料也有一些.rabbitmq:多.有一些不错的书,网上资料多.zeromq:少.没有专门写 ...

  6. ActiveMQ producer同步/异步发送消息

    http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式,可以通过代码配置: ((ActiveMQConnection)co ...

  7. ActiveMQ(2)---ActiveMQ原理分析之消息发送

    持久化消息和非持久化消息的发送策略 消息同步发送和异步发送 ActiveMQ支持同步.异步两种发送模式将消息发送到broker上.同步发送过程中,发送者发送一条消息会阻塞直到broker反馈一个确认消 ...

  8. activemq安装与简单消息发送接收实例

    安装环境:Activemq5.11.1, jdk1.7(activemq5.11.1版本需要jdk升级到1.7),虚拟机: 192.168.147.131 [root@localhost softwa ...

  9. Kafka学习笔记(6)----Kafka使用Producer发送消息

    1. Kafka的Producer 不论将kafka作为什么样的用途,都少不了的向Broker发送数据或接受数据,Producer就是用于向Kafka发送数据.如下: 2. 添加依赖 pom.xml文 ...

随机推荐

  1. 【Selenium2】【Jenkins】

    1. 下载Tomcat ,Windows7 环境,http://tomcat.apache.org/  我下载的是版本8 2. 下载Jenkins,Windows7 环境,http://jenkins ...

  2. Centos7:查看某个端口被哪个进程占用

    查看端口被哪个进程使用的命令 netstat -lnp | grep 参考: https://blog.csdn.net/u010886217/article/details/83626236 htt ...

  3. 关于AutoMApping 实体映射

    安装AutoMapping包 把订单实体映射成订单DTO实体 .ReverseMap()加上这个方法后 下面自定义 映射规则  第一个就是来源对象 第二个就是目标对象 https://www.cnbl ...

  4. vuex深入理解 modules

    一.什么是module? 背景:在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理 ...

  5. 关于js函数,方法,对象实例的一些说明

    朋友们大家好,好久没有更新文章了,最近正好有空就想着写点什么吧,加上这段时间总是能听到一些朋友们问关于js函数,方法,对象实例到底有什么区别这个问题,所以今天就献丑来简单说明一些吧! 其实这些主要都是 ...

  6. Qt5标准文件对话框类

    getOpenFileName()函数返回用户选择的文件名,其函数形式如下: QString QFileDialog::getOpenFileName(QWidget *parent = Q_NULL ...

  7. 电脑用HDMI线分屏后,耳机或音箱没声音之完美解决!

    现今,由于工作需要,很多人都偏爱给自己的电脑进行分屏,两个显示器同时连接在一台电脑上,并进行“扩展这些功能显示”,从而大大提高了工作积极性和工作效率.本人在进行分屏后遇到了耳机没有声音的问题,并进行了 ...

  8. JavaScript 第六章总结: Getting to know the DOM

    前言 这一章节介绍 DOM, 使用 DOM 的目的是使的网页能够变得 dynamic,使得 pages that react, that respond, that update themselves ...

  9. 雷林鹏分享:服务器上的 XML

    服务器上的 XML XML 文件是类似 HTML 文件的纯文本文件. XML 能够通过标准的 Web 服务器轻松地存储和生成. 在服务器上存储 XML 文件 XML 文件在 Internet 服务器上 ...

  10. 尝试重新(多次反复)处理某个逻辑的示例(good)

    以下例程的优点: 1.可以重新尝试某个动作 2.另外,在重新尝试的同时,可以做一些逻辑判断及标记的初始化 public static bool RetryLogin()        {        ...