ActiveMQ topic 普通订阅和持久订阅
直观的结果:当生产者向 topic 发送消息,
1. 若不存在持久订阅者和在线的普通订阅者,这个消息不会保存,当普通订阅者上线后,它是收不到消息的。
2. 若存在离线的持久订阅者,broker 会为该持久订阅者保存消息,当该持久订阅者上线后,会收到消息。
本质:producer 发送消息给 topic,broker 接收消息并且分发给 consumers。consumers 包括持久订阅者和在线的普通订阅者,对于持久订阅者,broker 把消息添加到它的 message cursor 中;对于普通订阅者,broker 直接分发消息。
如果,1个 topic 有2个持久订阅者,并且这2个持久订阅者都不在线,这时 producer 向 topic 发送1条消息,则 broker 会保存2条消息。因此,如果1个 topic 有很多不在线的持久订阅者,会导致 broker 消耗过多存储。
对于持久化的消息,这很好验证:为方便查看消息,将 broker 持久化方式配置为jdbc,则可以在 ACTIVEMQ_MSGS 表中看到持久化消息。
持久订阅者1:
new ActiveMQConnectionFactory("tcp://localhost:61616?jms.clientID=10086");
...
TopicSubscriber consumer = session.createDurableSubscriber(destination, "subscriber_zhang");
持久订阅者2:
new ActiveMQConnectionFactory("tcp://localhost:61616?jms.clientID=10087");
...
TopicSubscriber consumer = session.createDurableSubscriber(destination, "subscriber_zhang");
对于持久消息,验证 broker 为每个持久订阅者保存1条消息:
1. 启动 broker;
2. 分别启动2个持久订阅者,然后关闭它们,这样 broker 有了2个离线的持久订阅者;
3. 启动 producer 向 topic 发送1条消息;
4. 查看 ACTIVEMQ_MSGS 表
对于非持久消息,直接跟代码了,这里不说明。
下图是 Topic 接收消息并分发的调用栈:

// org.apache.activemq.broker.region.policy.SimpleDispatchPolicy
// 分发策略很简单,就是遍历consumers
public boolean dispatch(MessageReference node, MessageEvaluationContext msgContext, List<Subscription> consumers)
throws Exception {
int count = 0;
for (Subscription sub : consumers) {
// Don't deliver to browsers
if (sub.getConsumerInfo().isBrowser()) {
continue;
}
// Only dispatch to interested subscriptions
if (!sub.matches(node, msgContext)) {
sub.unmatched(node);
continue;
} //持久化订阅是 DurableTopicSubscription
//普通订阅是 TopicSubscription
sub.add(node);
count++;
} return count > 0;
}
持久化订阅:
// org.apache.activemq.broker.region.DurableTopicSubscription
public void add(MessageReference node) throws Exception {
if (!active.get() && !keepDurableSubsActive) {
return;
}
// 调用 PrefetchSubscription.add
super.add(node);
} // org.apache.activemq.broker.region.PrefetchSubscription
public void add(MessageReference node) throws Exception {
synchronized (pendingLock) {
// The destination may have just been removed...
if( !destinations.contains(node.getRegionDestination()) && node!=QueueMessageReference.NULL_MESSAGE) {
// perhaps we should inform the caller that we are no longer valid to dispatch to?
return;
} // Don't increment for the pullTimeout control message.
if (!node.equals(QueueMessageReference.NULL_MESSAGE)) {
enqueueCounter++;
}
//首先加入到 message cursor 中,pending 类型为 StoreDurableSubscriberCursor
pending.addMessageLast(node);
}
dispatchPending();
}
持久化订阅者上线后,也会触发消息分发动作即 dispatchPending,调用栈如下图:

持久化订阅者使用的 message cursor 是 StoreDurableSubscriberCursor。
普通订阅:
org.apache.activemq.broker.region.TopicSubscription.add(MessageReference node)
ActiveMQ topic 普通订阅和持久订阅的更多相关文章
- ActiveMQ 持久订阅者,执行结果与初衷相违背,验证离线订阅者无效,问题解决
导读 最新在接触ActiveMQ,里面有个持久订阅者模块,功能是怎么样也演示不出来效果.配置参数比较简单(配置没几个参数),消费者第一次运行时,需要指定ClientID(此时Broker已经记录离线订 ...
- JMS学习(六)--提高非持久订阅者的可靠性 以及 订阅恢复策略
一,非持久订阅者 和 实时消费消息 在这篇文章中区分了Domain为Pub/Sub.Destination为Topic时,消费者有两种:持久订阅者 和 非持久订阅者. 对于持久订阅者而言,只要订阅了某 ...
- JMS学习七(ActiveMQ之Topic的持久订阅)
非持久化订阅持续到它们订阅对象的生命周期.这意味着,客户端只能在订阅者活动时看到相关主题发布的消息.如果订阅者不活动,它会错过相关主题的消息.如果花费较大的开销,订阅者可以被定义为durable(持久 ...
- ActiveMQ queue和topic,持久订阅和非持久订阅
消息的 destination 分为 queue 和 topic,而消费者称为 subscriber(订阅者).queue 中的消息只会发送给一个订阅者,而 topic 的消息,会发送给每一个订阅者. ...
- JMS学习(五)--ActiveMQ中的消息的持久化和非持久化 以及 持久订阅者 和 非持久订阅者之间的区别与联系
一,消息的持久化和非持久化 ①DeliveryMode 这是传输模式.ActiveMQ支持两种传输模式:持久传输和非持久传输(persistent and non-persistent deliver ...
- activemq的高级特性:消息持久订阅
activemq的高级特性之消息持久订阅 如果采用topic模式发送的时候,mq关闭了或消费者关闭了.在启动的时候,就会收不到mq发送的消息,所以就会出现消息持久订阅. 消息持久订阅:第一:消息要持久 ...
- ActiveMQ 事务、集群、持久订阅者、ActiveMQ监控
JMS介绍 JMS是什么? JMS的全称Java Message Service,既Java消息服务. JMS是SUN提供的旨在统一各种MOM(Message-Oriented Middleware) ...
- activemq订阅发布模式(非持久订阅)
生产者JMSProducer: package com.sun.test.aircraft.activemq.topic; import org.apache.activemq.ActiveMQCon ...
- ActiveMQ 复杂类型的发布与订阅
很久没po文章了,但是看到.Net里关于ActiveMQ发送复杂类型的文章确实太少了,所以贴出来和大家分享 发布: //消息发布 public class Publisher { private IC ...
随机推荐
- 【Java】【THINK】
1. 新建类,应优先考虑“组织”对象,而不是继承.这样可以保持清爽. 2. Java对象&对象句柄: 声明了一个类型的变量也就是声明了一个该类型的对象.但是这个对象只是个抽象的概念,并不会在内 ...
- 【Java】【集合】
[1. ]HashMap,LinkedHashMap,TreeMap对比 共同点: HashMap,LinkedHashMap,TreeMap都属于Map:Map 主要用于存储键(key)值(valu ...
- CentOS7 使用firewalld打开关闭防火墙以及端口
1.firewalld的基本使用 启动 systemctl start firewalld 关闭 systemctl stop firewalld 查看状态 systemctl status fire ...
- 如何将购物车信息存到Redis中?
存到Redis中,好处是速度快.毕竟写到硬盘需要更多的时间.加入购物车的功能,操作很频繁,可以通过Redis快速写入,移除,修改. 用什么方式呢? 传统的KEY,VALUE不太合适,每次增加修改,都要 ...
- 《剑指offer》第六十题(n个骰子的点数)
// 面试题60:n个骰子的点数 // 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s.输入n,打印出s // 的所有可能的值出现的概率. #include <iostream> ...
- Ubuntu16.04 上安装MySQL5.7
Ubuntu版本:16.04.4 1.先更新最新的源 sudo apt-get update 2.查看是否已经安装过mysql sudo netstat -tap | grep mysq 如果没有安装 ...
- JAVA基础知识总结:一到二十二全部总结
>一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...
- css无定宽水平居中
转载:http://www.cnblogs.com/jogen/p/5213566.html 这个博客的菜单ui还是棒棒的. 方法一 思路:显示设置父元素为:table,子元素为:cell-table ...
- Spring Boot入门第一天:Hello, Spring Boot!
原文链接 1. 新建一个Maven Web项目. 2. 配置pom.xml文件. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ...
- Linux虚拟机安装VMware Tools
选择虚拟机-->install VMware Tools # 新建一个文件夹用来挂载光驱 mkdir /mnt/cdrom # 挂载光驱到指定文件夹 mount /dev/sr0 /mnt/cd ...