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. P1948 [USACO08JAN]电话线Telephone Lines

    传送门 思路: 二分+最短路径:可以将长度小于等于 mid 的边视为长度为 0 的边,大于 mid 的边视为长度为 1 的边,最后用 dijkstra 检查 d [ n ] 是否小于等于 k 即可. ...

  2. CAP原则

    CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性). Availability(可用性).Partition tolerance(分区容错性),三者不可兼得 分布式系 ...

  3. Ubuntu 编译安装 Xdebug

    安装xdebug 1.下载 https://xdebug.org/download.php 找到PHP5.6对应的版本 https://xdebug.org/files/xdebug-2.5.5.tg ...

  4. Qt532.【转】Qt在pro中设置运行时库MT、MTd、MD、MDd,只适合VS版本的Qt

    ZC:具体应该设置 什么参数,可以参看 自己转载的文章:"VC.[转]采用_beginthread__beginthreadex函数创建多线程 - CppSkill - 博客园.html&q ...

  5. Qt532.QString_填充字符

    1.代码: void MainWindow::on_pushButton_clicked() { QString str = "; QString str01 = str.leftJusti ...

  6. PCA分析和因子分析

    #由此说明使用prcomp函数时,必须使用标准化过的原始数据.如果使用没有标准化的raw数据(不是相关系数矩阵或者协方差矩阵),必须将参数scale. = T <result>$sdev ...

  7. 学习笔记50—多重假设检验与Bonferroni校正、FDR校正

    总结起来就三句话: (1)当同一个数据集有n次(n>=2)假设检验时,要做多重假设检验校正 (2)对于Bonferroni校正,是将p-value的cutoff除以n做校正,这样差异基因筛选的p ...

  8. DAY1 计算机组成和操作系统

    一.编程与编程目的 1.编程语言的定义 编程语言是人与计算机之间沟通的介质 2.什么是编程 编程就是程序员通过编程语言让计算机实现所想做的事 3.编程的目的 解放人力,让计算机按照人的逻辑思维进行工作 ...

  9. python实战小程序之购物车

    # Author:南邮吴亦凡 # 商品列表 product_list = [ ('Iphone',5800), # 逗号一定不可以省略! ('Mac',4800), ('smartphone',400 ...

  10. 日常英语---十三、MapleStory/Monsters/Level 11-20(邪恶之眼)

    日常英语---十三.MapleStory/Monsters/Level 11-20(邪恶之眼) 一.总结 一句话总结: evil ['ivl] A stronger version of Evil E ...