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 ...
随机推荐
- [HTML]html读取本地文件并显示
<html> <body> <script script type="text/javascript"> function show() { v ...
- 《剑指offer》第六十六题(构建乘积数组)
// 面试题66:构建乘积数组 // 题目:给定一个数组A[0, 1, …, n-1],请构建一个数组B[0, 1, …, n-1],其 // 中B中的元素B[i] =A[0]×A[1]×… ×A[i ...
- 学习笔记1—python基础
1.安装pip: python -m pip install -U pip (打开命令行窗口:Anaconda Prompt) 升级:python -m pip install --upgrade p ...
- Django 基础介绍
Django 介绍 Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架,由 ...
- 响应式图片 (responsive image)
更新 : 2019-02-21 除了写 srcset sizes 还有一种 x1, x2, x3, x4 的写法. 我们对比一下 假设 pc 希望是 1000w mobile 希望是 300w siz ...
- Python&HDF5目录
最近一直没更新python&量化的博客,是因为忙于看HDF5的书,写VNPY框架,学scrapy爬虫. 本来写博客的目的就是为了当作一种教材,当遇到不会的问题过来找答案. 对于HDF5下面这本 ...
- 在不进入Guest OS的情况下,取得Guest OS的IP地址
因为是个Headless 服务器,总是需要GUI VNC 到 Host OS, 然后进入里面的虚拟机,打 ipconfig / ifconfig ,非常的不方便. 查了网上,找到上面的方法 1)确保 ...
- java---->Itellij idea报错:错误: 找不到或无法加载主类 main
没有设置好正确的类路径 点击上面圈红色处,在点击Edit Configuration,进入下面设置界面 切换到下面这个界面 红色×消失,运行正常,截图如下
- JS获取系统时间--JavaScript基础
1.网页中实时显示当前时间 <!DOCTYPE html><html lang="en"><head> <meta charset=&qu ...
- C#获取网页的HTML码、下载网站图片
1.根据URL请求获取页面HTML代码 /// <summary> /// 获取网页的HTML码 /// </summary> /// <param name=" ...