ActiveMQ producer不断发送消息,会导致broker内存耗尽吗?
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内存耗尽吗?的更多相关文章
- kafka producer batch 发送消息
1. 使用 KafkaProducer 发送消息,是按 batch 发送的,producer 首先把消息放入 ProducerBatch 中: org.apache.kafka.clients.pro ...
- producer怎样发送消息到指定的partitions
http://www.aboutyun.com/thread-9906-1-1.html http://my.oschina.net/u/591402/blog/152837 https://gith ...
- ActiveMQ producer 提交事务时突然宕机,会发生什么
producer 在提交事务时,发生宕机,commit 的命令没有发送到 broker,这时会发生什么? ActiveMQ 开启事务发送消息的步骤: session.getTransactionCon ...
- 17 个方面,综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
原文:https://mp.weixin.qq.com/s/lpsQ3dEZHma9H0V_mcxuTw 一.资料文档 二.开发语言 三.支持的协议 四.消息存储 五.消息事务 六.负载均衡 七.集群 ...
- 综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
来源:http://t.cn/RVDWcfe 一.资料文档 Kafka:中.有kafka作者自己写的书,网上资料也有一些.rabbitmq:多.有一些不错的书,网上资料多.zeromq:少.没有专门写 ...
- ActiveMQ producer同步/异步发送消息
http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式,可以通过代码配置: ((ActiveMQConnection)co ...
- ActiveMQ(2)---ActiveMQ原理分析之消息发送
持久化消息和非持久化消息的发送策略 消息同步发送和异步发送 ActiveMQ支持同步.异步两种发送模式将消息发送到broker上.同步发送过程中,发送者发送一条消息会阻塞直到broker反馈一个确认消 ...
- activemq安装与简单消息发送接收实例
安装环境:Activemq5.11.1, jdk1.7(activemq5.11.1版本需要jdk升级到1.7),虚拟机: 192.168.147.131 [root@localhost softwa ...
- Kafka学习笔记(6)----Kafka使用Producer发送消息
1. Kafka的Producer 不论将kafka作为什么样的用途,都少不了的向Broker发送数据或接受数据,Producer就是用于向Kafka发送数据.如下: 2. 添加依赖 pom.xml文 ...
随机推荐
- 突变注释工具SnpEff,Annovar,VEP,oncotator比较分析--转载
https://www.jianshu.com/p/6284f57664b9 目前对于variant进行注释的软件主要有4个: Annovar, SnpEff, VEP(variant Effect ...
- vue--移动端兼容问题
click的300ms延迟: 引入fastclick库来解决 输入命令 npm install fastclick 在main.js导入 import Vue from 'vue' import Ap ...
- BaseEditor
using UnityEngine;using System.Collections.Generic;using UnityEditor;using System.Text;using System. ...
- 【BZOJ】4013: [HNOI2015]实验比较
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4013 中第i 条涉及的图片对为(KXi, Xi),判断要么是KXi < Xi ,要么 ...
- Redis 个人理解总结
一.什么是Redis ? Redis(remote dictionnary server)是一个key-value存储系统.Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可 ...
- 【SQL Prompt】SQL Prompt7.2下载及破解教程
基本介绍 SQL Prompt能根据数据库的对象名称,语法和用户编写的代码片段自动进行检索,智能的为用户提供唯一合适的代码选择.自动脚本设置为用户提供了简单的代码易读性--这在开发者使用的是不大熟悉的 ...
- 前端阶段_html部分
HTML 1.html5的第一行一定是<!DOCTYPE html>,h4太长,而且一般ide中会自动加载,了解即可. 2.h5的整个页面被<html></html> ...
- [原][osg]osgconv浅析
查看osgconv.cpp main函数在533行 osg::ArgumentParser arguments(&argc,argv); //........一堆功能不管,先看一下文件读写 F ...
- EF延迟加载和懒加载
EF默认是延迟加载的 延迟加载就是刚开始只会读取当前实体对应表的数据 关联表的数据不会读取 只有下面条件用到了才会再去读取 所以可能会造成N次读取数据库 需要在实体的属性加virtual关键字 延迟 ...
- 项目上有红色感叹号, 一般就是依赖包有问题, remove依赖,重新加载,maven的也行可认删除,自己也会得新加载
项目上的红色叹号, 要下面提示: "Problems" 里的errors , 看是什么错误, 一般是由于网络等原因, 依赖没有下载完整, 只有文件名字对了, 内容不全, ...