RocketMQ系列(五)广播与延迟消息
今天要给大家介绍RocketMQ中的两个功能,一个是“广播”,这个功能是比较基础的,几乎所有的mq产品都是支持这个功能的;另外一个是“延迟消费”,这个应该算是RocketMQ的特色功能之一了吧。接下来,我们就分别看一下这两个功能。
广播
广播是把消息发送给订阅了这个主题的所有消费者。这个定义很清楚,但是这里边的知识点你都掌握了吗?咱们接着说“广播”的机会,把消费者这端的内容好好和大家说说。
- 首先,消费者端的概念中,最大的应该是消费者组,一个消费者组中可以有多个消费者,这些消费者必须订阅同一个Topic。
- 那么什么算是一个消费者呢?我们在写消费端程序时,看到了setConsumeThreadMax这个方法,设置消费者的线程数,难道一个线程就是一个消费者?错!这里的一个消费者是一个进程,你可以理解为ip+端口。如果在同一个应用中,你实例化了两个消费者,这两个消费者配置了相同的消费者组名称,那么应用程序启动时会报错的,这里不给大家演示了,感兴趣的小伙伴私下里试一下吧。
- 同一个消息,可以被不同的消费者组同时消费。假设,我有两个消费者组cg-1和cg-2,这两个消费者组订阅了同一个Topic,那么这个Topic的消息会被cg-1和cg-2同时消费。那这是不是广播呢?错!当然不是广播,广播是同一个消费者组中的多个消费者都消费这个消息。如果配置的不是广播,像前几个章节中的那样,一个消息只能被一个消费者组消费一次。
好了,说了这么多,我们实验一下吧,先把消费者配置成广播,如下:
@Bean(name = "broadcast", initMethod = "start",destroyMethod = "shutdown")
public DefaultMQPushConsumer broadcast() throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("broadcast");
consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
consumer.subscribe("cluster-topic","*");
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
return consumer;
}
- 其中,NameServer,订阅的Topic都没有变化。
- 注意其中
consumer.setMessageModel(MessageModel.BROADCASTING);这段代码,设置消费者为广播。咱们可以看一下,MessageModel枚举中只有两个值,BROADCASTING和CLUSTERING,默认为CLUSTERING。
因为要测试广播,所以我们要启动多个消费者,还记得什么是消费者吗?对了,一个ip+端口算是一个消费者,在这里我们启动两个应用,端口分别是8080和8081。发送端的程序不变,如下:
@Test
public void producerTest() throws Exception {
for (int i = 0;i<5;i++) {
MessageExt message = new MessageExt();
message.setTopic("cluster-topic");
message.setKeys("key-"+i);
message.setBody(("this is simpleMQ,my NO is "+i+"---"+new Date()).getBytes());
SendResult sendResult = defaultMQProducer.send(message);
System.out.println("i=" + i);
System.out.println("BrokerName:" + sendResult.getMessageQueue().getBrokerName());
}
}
我们执行一下发送端的程序,日志如下:
i=0
BrokerName:broker-a
i=1
BrokerName:broker-a
i=2
BrokerName:broker-b
i=3
BrokerName:broker-b
i=4
BrokerName:broker-b
再来看看8080端口的应用后台打印出来的日志:

消费了5个消息,再看看8081的后台打印的日志,

也消费了5个。两个消费者同时消费了消息,这就是广播。有的小伙伴可能会有疑问了,如果不设置广播,会怎么样呢?私下里实验一下吧,上面的程序中,只要把设置广播的那段代码注释掉就可以了。运行的结果当然是只有一个消费者可以消费消息。
延迟消息
延迟消息是指消费者过了一个指定的时间后,才去消费这个消息。大家想象一个电商中场景,一个订单超过30分钟未支付,将自动取消。这个功能怎么实现呢?一般情况下,都是写一个定时任务,一分钟扫描一下超过30分钟未支付的订单,如果有则被取消。这种方式由于每分钟查询一下订单,一是时间不精确,二是查库效率比较低。这个场景使用RocketMQ的延迟消息最合适不过了,我们看看怎么发送延迟消息吧,发送端代码如下:
@Test
public void producerTest() throws Exception {
for (int i = 0;i<1;i++) {
MessageExt message = new MessageExt();
message.setTopic("cluster-topic");
message.setKeys("key-"+i);
message.setBody(("this is simpleMQ,my NO is "+i+"---"+new Date()).getBytes());
message.setDelayTimeLevel(2);
SendResult sendResult = defaultMQProducer.send(message);
System.out.println("i=" + i);
System.out.println("BrokerName:" + sendResult.getMessageQueue().getBrokerName());
}
}
- 我们只是增加了一句
message.setDelayTimeLevel(2); - 为了方便,这次我们只发送一个消息。
setDelayTimeLevel是什么意思,设置的是2,难道是2s后消费吗?怎么参数也没有时间单位呢?如果我要自定义延迟时间怎么办?我相信很多小伙伴都有这样的疑问,我也是带着这样的疑问查了很多资料,最后在RocketMQ的Github官网上看到了说明,
- 在RocketMQ的源码中,有一个MessageStoreConfig类,这个类中定义了延迟的时间,我们看一下,
// org/apache/rocketmq/store/config/MessageStoreConfig.java
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
- 我们在程序中设置的是2,那么这个消息将在5s以后被消费。
- 目前RocketMQ还不支持自定义延迟时间,延迟时间只能从上面的时间中选。如果你非要定义一个时间怎么办呢?RocketMQ是开源的,下载代码,把上面的时间改一下,再打包部署,就OK了。
再看看消费端的代码,
@Bean(name = "broadcast", initMethod = "start",destroyMethod = "shutdown")
public DefaultMQPushConsumer broadcast() throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("broadcast");
consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
consumer.subscribe("cluster-topic","*");
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
for (MessageExt msg : msgs) {
Date now = new Date();
System.out.println("消费时间:"+now);
Date msgTime = new Date();
msgTime.setTime(msg.getBornTimestamp());
System.out.println("消息生成时间:"+msgTime);
System.out.println(new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
return consumer;
}
- 我们还是使用广播的模式,没有变。
- 打印出了当前的时间,这个时间就是消费的时间。
- 通过msg.getBornTimestamp()方法,获得了消息的生成时间,也打印出来,看看是不是延迟5s。
启动两个消费者8080和8081,发送消息,再看看消费者的后台日志,
消费时间:Thu Jun 11 14:45:53 CST 2020
消息生成时间:Thu Jun 11 14:45:48 CST 2020
this is simpleMQ,my NO is 0---Thu Jun 11 14:45:47 CST 2020
我们看到消费时间比生成时间晚5s,符合我们的预期。这个功能还是比较实用的,如果能够自定义延迟时间就更好了。
总结
RocketMQ的这两个知识点还是比较简单的,大家要分清楚什么是消费者组,什么是消费者,什么是消费者线程。另外就是延迟消息是不支持自定义的,大家可以在Github上看一下源码。好了~今天就到这里了。
RocketMQ系列(五)广播与延迟消息的更多相关文章
- RocketMQ系列(七)事务消息(数据库|最终一致性)
终于到了今天了,终于要讲RocketMQ最牛X的功能了,那就是事务消息.为什么事务消息被吹的比较热呢?近几年微服务大行其道,整个系统被切成了多个服务,每个服务掌管着一个数据库.那么多个数据库之间的数据 ...
- RocketMQ延迟消息的代码实战及原理分析
RocketMQ简介 RocketMQ是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的.高可靠.万亿级容量.灵活可伸缩的消息发布与订阅服务. 它前身是MetaQ,是阿里基于Kafka ...
- 阿里云RocketMQ定时/延迟消息队列实现
新的阅读体验:http://www.zhouhong.icu/post/157 一.业务需求 需要实现一个提前二十分钟通知用户去做某件事的一个业务,拿到这个业务首先想到的最简单得方法就是使用Redis ...
- Alibaba-技术专区-RocketMQ 延迟消息实现原理和源码分析
痛点背景 业务场景 假设有这么一个需求,用户下单后如果30分钟未支付,则该订单需要被关闭.你会怎么做? 之前方案 最简单的做法,可以服务端启动个定时器,隔个几秒扫描数据库中待支付的订单,如果(当前时间 ...
- SpringBoot - 集成RocketMQ实现延迟消息队列
目录 前言 环境 具体实现 前言 RocketMQ是阿里巴巴在2012年开源的分布式消息中间件,记录下SpringBoot整合RocketMQ的方式,RocketMQ的安装可以查看:Windows下安 ...
- RocketMQ源码详解 | Broker篇 · 其四:事务消息、批量消息、延迟消息
概述 在上文中,我们讨论了消费者对于消息拉取的实现,对于 RocketMQ 这个黑盒的心脏部分,我们顺着消息的发送流程已经将其剖析了大半部分.本章我们不妨乘胜追击,接着讨论各种不同的消息的原理与实现. ...
- EnjoyingSoft之Mule ESB开发教程系列第五篇:控制消息的流向-数据路由
目录 1. 使用场景 2. 基于消息头的路由 2.1 使用JSON提交订单的消息 2.2 使用XML提交订单的消息 2.3 使用Choice组件判断订单格式 3. 基于消息内容的路由 4. 其他控制流 ...
- SpringCloud 2020.0.4 系列之 Stream 延迟消息 的实现
1. 概述 老话说的好:对待工作要有责任心,不仅要完成自己的部分,还要定期了解整体的进展. 言归正传,我们在开发产品时,常常会遇到一段时间后检查状态的场景,例如:用户下单场景,如果订单生成30分钟后, ...
- 17 个方面,综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
原文:https://mp.weixin.qq.com/s/lpsQ3dEZHma9H0V_mcxuTw 一.资料文档 二.开发语言 三.支持的协议 四.消息存储 五.消息事务 六.负载均衡 七.集群 ...
随机推荐
- 【比较】粒子群算法PSO 和 遗传算法GA 的相同点和不同点
目录 PSO和GA的相同点 PSO和GA不同点 粒子群算法(PSO)和遗传算法(GA)都是优化算法,都力图在自然特性的基础上模拟个体种群的适应性,它们都采用一定的变换规则通过搜索空间求解. PSO和G ...
- Django之AJAX简单使用
AJAX简介: AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传输 ...
- Jenkins-gogs安装及使用
很多同学可能第一次了解什么是ci-cd,什么是Jenkins,首先会介绍下cicd的概念及应用场景,之后再详细介绍下Jenkins的概念.安装及使用. 什么是CI-CD? 首先明确CI-CD是一种技术 ...
- 移除项目中的UIWebView
1,AFN升级4.0 2,代码中搜索UIWebView移除相关文件 3,检查库是否使用的UIWebView 参考 https://www.jianshu.com/p/3a645500d461
- 关于Java Web结构和SSM框架的理解
Java Web常见的三层结构 表现层:也就是Web层,常见的框架有Spring MVC.Struts2 ,并包括用于展示的界面,如JSP界面:业务层:Service层,专注于业务逻辑的实现:持久层: ...
- Kubernetes学习笔记(八):Deployment--声明式的升级应用
概述 本文核心问题是:如何升级应用. 对于Pod的更新有两种策略: 一是删除全部旧Pod之后再创建新Pod.好处是,同一时间只会有一个版本的应用存在:缺点是,应用有一段时间不可用. 二是先创建新Pod ...
- UIAutomator2的API文档(二)
1.设备屏幕事件 熄灭屏幕d.screen_off() 唤醒屏幕d.screen_on() 屏蔽状态d.info.get('screenOn')#返回True or False 解锁屏幕d.unloc ...
- echarts实现漏斗转化率图表效果
1.在用echarts实现图表的旅途中遇到这样一个需求,用柱图展示漏斗转化效果,下图展示: 别的不多说了,就说解决方式吧,用的series中的markpoint来实现. option.series[0 ...
- WEB APPLICATION PENETRATION TESTING NOTES
此文转载 XXE VALID USE CASE This is a nonmalicious example of how external entities are used: <?xml v ...
- PAT1090 危险品装箱 (25分) ——值得留意的map用法(int型与vector型的关联)
1090 危险品装箱 (25分) 集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里.比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸. 本题给定一张不相容物品的清单,需要你 ...