RocketMQ简介
RocketMQ是由阿里捐赠给Apache的一款低延迟、高并发、高可用、高可靠的分布式消息中间件。经历
了淘宝双十一的洗礼。RocketMQ既可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备
互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性。
官方文档: https://rocketmq.apache.org/docs/quick-start/
github中文主页:https://github.com/apache/rocketmq/tree/master/docs/cn
核心概念
- Topic:消息主题,一级消息类型,生产者向其发送消息。
- Message:生产者向Topic发送并最终传送给消费者的数据消息的载体。
- 消息属性:生产者可以为消息定义的属性,包含Message Key和Tag。
- Message Key:消息的业务标识,由消息生产者(Producer)设置,唯一标识某个业务逻辑。
- Message ID:消息的全局唯一标识,由消息队列RocketMQ系统自动生成,唯一标识某条消息。
- Tag:消息标签,二级消息类型,用来进一步区分某个Topic下的消息分类
- Producer:也称为消息发布者,负责生产并发送消息至Topic。
- Consumer:也称为消息订阅者,负责从Topic接收并消费消息。
- 分区:即Topic Partition,物理上的概念。每个Topic包含一个或多个分区。
- 消费位点:每个Topic会有多个分区,每个分区会统计当前消息的总条数,这个称为最大位点
MaxOffset;分区的起始位置对应的位置叫做起始位点MinOffset。 - Group:一类生产者或消费者,这类生产者或消费者通常生产或消费同一类消息,且消息发布或订
阅的逻辑一致。 - Group ID:Group的标识。
- 队列:个Topic下会由一到多个队列来存储消息。
- Exactly-Once投递语义:Exactly-Once投递语义是指发送到消息系统的消息只能被Consumer处理
且仅处理一次,即使Producer重试消息发送导致某消息重复投递,该消息在Consumer也只被消费
一次。 - 集群消费:一个Group ID所标识的所有Consumer平均分摊消费消息。例如某个Topic有9条消息,
一个Group ID有3个Consumer实例,那么在集群消费模式下每个实例平均分摊,只消费其中的3条
消息。 - 广播消费:一个Group ID所标识的所有Consumer都会各自消费某条消息一次。例如某个Topic有9
条消息,一个Group ID有3个Consumer实例,那么在广播消费模式下每个实例都会各自消费9条消
息。 - 定时消息:Producer将消息发送到消息队列RocketMQ服务端,但并不期望这条消息立马投递,而
是推迟到在当前时间点之后的某一个时间投递到Consumer进行消费,该消息即定时消息。 - 延时消息:Producer将消息发送到消息队列RocketMQ服务端,但并不期望这条消息立马投递,而
是延迟一定时间后才投递到Consumer进行消费,该消息即延时消息。 - 事务消息:RocketMQ提供类似X/Open XA的分布事务功能,通过消息队列RocketMQ的事务消息
能达到分布式事务的最终一致。 - 顺序消息:RocketMQ提供的一种按照顺序进行发布和消费的消息类型,分为全局顺序消息和分区
顺序消息。 - 全局顺序消息:对于指定的一个Topic,所有消息按照严格的先入先出(FIFO)的顺序进行发布和
消费。 - 分区顺序消息:对于指定的一个Topic,所有消息根据Sharding Key进行区块分区。同一个分区内
的消息按照严格的FIFO顺序进行发布和消费。Sharding Key是顺序消息中用来区分不同分区的关键
字段,和普通消息的Message Key是完全不同的概念。 - 消息堆积:Producer已经将消息发送到消息队列RocketMQ的服务端,但由于Consumer消费能力
有限,未能在短时间内将所有消息正确消费掉,此时在消息队列RocketMQ的服务端保存着未被消
费的消息,该状态即消息堆积。 - 消息过滤:Consumer可以根据消息标签(Tag)对消息进行过滤,确保Consumer最终只接收被
过滤后的消息类型。消息过滤在消息队列RocketMQ的服务端完成。 - 消息轨迹:在一条消息从Producer发出到Consumer消费处理过程中,由各个相关节点的时间、地
点等数据汇聚而成的完整链路信息。通过消息轨迹,您能清晰定位消息从Producer发出,经由消息
队列RocketMQ服务端,投递给Consumer的完整链路,方便定位排查问题。 - 重置消费位点:以时间轴为坐标,在消息持久化存储的时间范围内(默认3天),重新设置
Consumer对已订阅的Topic的消费进度,设置完成后Consumer将接收设定时间点之后由
Producer发送到消息队列RocketMQ服务端的消息。 - 死信队列:死信队列用于处理无法被正常消费的消息。当一条消息初次消费失败,消息队列
RocketMQ会自动进行消息重试;达到最大重试次数后,若消费依然失败,则表明Consumer在正
常情况下无法正确地消费该消息。此时,消息队列RocketMQ不会立刻将消息丢弃,而是将这条消
息发送到该Consumer对应的特殊队列中。
应用场景
- 削峰填谷:诸如秒杀、抢红包、企业开门红等大型活动时皆会带来较高的流量脉冲,或因没做相应
的保护而导致系统超负荷甚至崩溃,或因限制太过导致请求大量失败而影响用户体验,消息队列
RocketMQ可提供削峰填谷的服务来解决该问题。 - 异步解耦:交易系统作为淘宝和天猫主站最核心的系统,每笔交易订单数据的产生会引起几百个下
游业务系统的关注,包括物流、购物车、积分、流计算分析等等,整体业务系统庞大而且复杂,消
息队列RocketMQ可实现异步通信和应用解耦,确保主站业务的连续性。 - 顺序收发:细数日常中需要保证顺序的应用场景非常多,例如证券交易过程时间优先原则,交易系
统中的订单创建、支付、退款等流程,航班中的旅客登机消息处理等等。与先进先出FIFO(First In
First Out)原理类似,消息队列RocketMQ提供的顺序消息即保证消息FIFO。 - 分布式事务一致性:交易系统、支付红包等场景需要确保数据的最终一致性,大量引入消息队列
RocketMQ的分布式事务,既可以实现系统之间的解耦,又可以保证最终的数据一致性。 - 大数据分析:数据在“流动”中产生价值,传统数据分析大多是基于批量计算模型,而无法做到实时
的数据分析,利用阿里云消息队列RocketMQ与流式计算引擎相结合,可以很方便的实现业务数据
的实时分析。 - 分布式缓存同步:天猫双11大促,各个分会场琳琅满目的商品需要实时感知价格变化,大量并发访
问数据库导致会场页面响应时间长,集中式缓存因带宽瓶颈,限制了商品变更的访问流量,通过消
息队列RocketMQ构建分布式缓存,实时通知商品数据的变化
架构设计
RocketMQ架构上主要分为四部分,如上图所示:
- Producer:消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相
应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。 - Consumer:消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息
进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用
户的需求。 - NameServer:NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的
zookeeper,支持Broker的动态注册与发现。主要包括两个功能:Broker管理,NameServer接受
Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查
Broker是否还存活;路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用
于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集
群的路由信息,从而进行消息的投递和消费。NameServer通常也是集群的方式部署,各实例间相
互不进行信息通讯。Broker是向每一台NameServer注册自己的路由信息,所以每一个
NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,
Broker仍然可以向其它NameServer同步其路由信息,Producer,Consumer仍然可以动态感知
Broker的路由的信息。 - BrokerServer:Broker主要负责消息的存储、投递和查询以及服务高可用保证,为了实现这些功
能,Broker包含了以下几个重要子模块。
- Remoting Module:整个Broker的实体,负责处理来自clients端的请求。
- Client Manager:负责管理客户端(Producer/Consumer)和维护Consumer的Topic订阅信息
- Store Service:提供方便简单的API接口处理消息存储到物理硬盘和查询功能。
- HA Service:高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。
- Index Service:根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息
的快速查询。
RocketMQ Server安装
SpringBoot整合RocketMQ实现消息发送和接收
项目结构
第一步:我们新建一个父项目 rocketmq-test ,pom类型,主要是依赖管理,包括版本的管理,以及管
理module子项目
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>rocketmq-provider</module>
<module>rocketmq-consumer</module>
</modules>
<groupId>org.example</groupId>
<artifactId>rocketmq-test</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<springboot.version>2.3.2.RELEASE</springboot.version>
<rocketmq.version>2.2.0</rocketmq.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二步:新建消息生产者 rocketmq-provider 子项目
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rocketmq-test</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rocketmq-provider</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
新建项目配置文件 application.yml ,指定name-server,以及producer-group组
server:
port: 8081
servlet:
context-path: /
rocketmq:
name-server: *.*.*.*:9876
producer:
group: producer-demo1
新建消息生产者Service类 ProducerService
SpringBoot给我们提供了 RocketMQTemplate 模板类
package com.suqi.rocketmq;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Suqi
* @version 1.0
* @date 2022/5/11 11:17
* @desc
*/
@Component("producerService")
public class ProducerService {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/*** 发送简单消息 */
public void sendMessage() {
for (int i = 0; i < 10; i++) {
rocketMQTemplate.convertAndSend("java1234-rocketmq", "rocketmq大爷,你 好!" + i);
}
}
}
第三步:新建消息消费者 rocketmq-consumer 子项目
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rocketmq-test</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rocketmq-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
新建项目配置文件 application.yml ,指定name-server,以及consumer-group组
server:
port: 8084
servlet:
context-path: /
rocketmq:
name-server: 120.77.39.136:9876
consumer:
group: consumer-demo1
新建消息消费者Service类 ConsumerService ,监听消息,消费消息
@RocketMQMessageListener(topic = "java1234-rocketmq", consumerGroup = "${rocketmq.consumer.group}")
@Component
public class ConsumerService implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("收到消息内容:" + s);
}
}
启动类直接测试发送消息
先启动消费者,再开启生产者
@SpringBootApplication
public class RocketmqTestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(RocketmqTestApplication.class, args);
ProducerService producerService = (ProducerService) run.getBean("producerService");
producerService.sendMessage();
}
}
运行测试OK
RocketMQ发送同步消息
发送同步消息是指producer向 broker 发送消息,执行 API 时同步等待, 直到broker 服务器返回发送结
果;
相对异步发送消息,同步会阻塞线程,性能相对差点,但是可靠性高,这种方式得到广泛使用,比如:
短信通知,邮件通知,站内重要信息通知等。
RocketMQTemplate 给我们提供了syncSend方法(有多个重载),来实现发送同步消息;
这里执行完发送同步消息返回执行结果 SendResult ;
/*** 发送同步消息 */
public void sendSyncMessage() {
for (int i = 0; i < 10; i++) {
SendResult sendResult = rocketMQTemplate.syncSend("java1234-rocketmq", "rocketmq同步消息!" + i);
System.out.println(sendResult);
}
}
RocketMQ发送异步消息
发送异步消息是指producer向 broker 发送消息时指定消息发送成功及发送异常的回调方法,调用 API
后立即返回,producer发送消息线程不阻塞 ,消息发送成功或失败的回调任务在一个新的线程中执行
。
相对发送同步消息,异步消息性能更高,可靠性略差。适合对响应时间要求高的业务场景。
RocketMQTemplate 给我们提供了asyncSend方法(有多个重载),来实现发送异步消息;
/*** 发送异步消息 */
public void sendAsyncMessage() {
for (int i = 0; i < 10; i++) {
rocketMQTemplate.asyncSend("java1234-rocketmq", "rocketmg异步消息!" + i, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("发送成功!");
}
@Override
public void onException(Throwable throwable) {
System.out.println("发送失败!");
}
});
}
}
类似发送同步消息,多了一个SendCallback回调接口参数,实现onSuccess和onException方法,分别
表示异步发送成功和失败;
RocketMQ发送单向消息
发送单向消息是指producer向 broker 发送消息,执行 API 时直接返回,不等待broker 服务器的结果 。
这种方式主要用在不特别关心发送结果的场景,举例:日志发送;
RocketMQTemplate 给我们提供了sendOneWay方法(有多个重载),来实现发送单向消息;
/*** 发送单向消息 */
public void sendOneWayMessage() {
for (int i = 0; i < 10; i++) {
rocketMQTemplate.sendOneWay("java1234-rocketmq", "rocketmg单向消息!" + i);
}
}
RocketMQ消费者广播模式和负载均衡模式
广播模式是每个消费者,都会消费消息;
负载均衡模式是每一个消息只会被某一个消费者消费一次;
我们可以通过 @RocketMQMessageListener 的 messageModel 属性值来设置,
MessageModel.BROADCASTING 是广播模式,
MessageModel.CLUSTERING 是默认集群负载均衡模式;
简单理解: 集群负载模式说白了就是 发10条消息,一人个五条对半
广播模式就是 发10条消息,两个消费者都消费10条
RocketMQ实现顺序消息
rocketmq默认发送的消息是进入多个消息队列,然后消费端多线程并发消费,所以默认情况,不是顺序
消费消息的;
RocketMQTemplate 给我们提供了SendOrderly方法(有多个重载),来实现发送顺序消息;包括以下:
syncSendOrderly,发送同步顺序消息;
asyncSendOrderly,发送异步顺序消息;
sendOneWayOrderly,发送单向顺序消息;
发送端
hashKey参数,主要用来计算选择队列的,一般可以把订单ID,
产品ID作为参数值;
消费者端
监听器的consumeMode = ConsumeMode.ORDERLY设置好
@RocketMQMessageListener(topic = "java1234-rocketmq-orderly", consumerGroup = "${rocketmq.consumer.group}", consumeMode = ConsumeMode.ORDERLY)
@Component
public class ConsumerServiceOrderly implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("消费者:收到消息内容:" + s);
}
}
RocketMQ实现延迟消息
延迟消息
对于消息中间件来说,producer 将消息发送到mq的服务器上,但并不希望这条消息马上被消费,
而是推迟到当前时间节点之后的某个时间点,再将消息投递到 queue 中让 consumer 进行消费。
延迟消息的使用场景很多,一种比较常见的场景就是在电商系统中,订单创建后,会有一个等待用
户支付的时间窗口,一般为30分钟,30分钟后 customer 会收到这条订单消息,然后程序去订单表中检
查当前这条订单的支付状态,如果是未支付的状态,则自动清理掉,这样就不需要使用定时任务的方式
去处理了。
Rocket的延迟消息
RocketMQ 支持定时的延迟消息,但是不支持任意时间精度,仅支持特定的 level,例如定时 5s,
10s, 1m 等。其中,level=0 级表示不延时,level=1 表示 1 级延时,level=2 表示 2 级延时,以此类
推
messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
timeout=3000 代表的是消息发送超时时间
/*** 发送延迟消息 */
public void sendDelayMessage() {
rocketMQTemplate.syncSend("java1234-rocketmq", MessageBuilder.withPayload("rocketmq延迟1秒消息").build(), 3000, 1);
rocketMQTemplate.syncSend("java1234-rocketmq", MessageBuilder.withPayload("rocketmq延迟5秒消息").build(), 3000, 2);
rocketMQTemplate.syncSend("java1234-rocketmq", MessageBuilder.withPayload("rocketmq延迟10秒消息").build(), 3000, 3);
}
RocketMQ实现事务消息
事务消息是RocketMQ提供的非常重要的一个特性,在4.x版本之后开源,可以利用事务消息轻松地实现
分布式事务。
RocketMQ在其消息定义的基础上,对事务消息扩展了两个相关的概念:
Half(Prepare) Message——半消息(预处理消息)
半消息是一种特殊的消息类型,该状态的消息暂时不能被Consumer消费。当一条事务消息被成功投递
到Broker上,但是Broker并没有接收到Producer发出的二次确认时,该事务消息就处于"暂时不可被消
费"状态,该状态的事务消息被称为半消息。
Message Status Check——消息状态回查
由于网络抖动、Producer重启等原因,可能导致Producer向Broker发送的二次确认消息没有成功送
达。如果Broker检测到某条事务消息长时间处于半消息状态,则会主动向Producer端发起回查操作,查
询该事务消息在Producer端的事务状态(Commit 或 Rollback)。可以看出,Message Status Check主要
用来解决分布式事务中的超时问题。
- 应用模块遇到要发送事务消息的场景时,先发送prepare消息给MQ。
- prepare消息发送成功后,应用模块执行数据库事务(本地事务)。
- 根据数据库事务执行的结果,再返回Commit或Rollback给MQ。
- 如果是Commit,MQ把消息下发给Consumer端,如果是Rollback,直接删掉prepare消息。
- 第3步的执行结果如果没响应,或是超时的,启动定时任务回查事务状态(最多重试15次,超过了
默认丢弃此消息),处理结果同第4步。 - MQ消费的成功机制由MQ自己保证。
具体实例:
/*** 发送事务消息 */
public void sendTransactionMessage() { // 构造消息
Message msg = MessageBuilder.withPayload("rocketmq事务消息-01").build();
rocketMQTemplate.sendMessageInTransaction("java1234-transaction-rocketmq", msg, null);
}
@RocketMQTransactionListener
class TransactionListenerImpl implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// ... local transaction process, return bollback, commit or unknown System.out.println("executeLocalTransaction"); return RocketMQLocalTransactionState.UNKNOWN; }@Override public RocketMQLocalTransactionState checkLocalTransaction(Message msg) { // ... check transaction status and return bollback, commit or unknown
System.out.println("checkLocalTransaction");
return RocketMQLocalTransactionState.COMMIT;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
return null;
}
}
定义本地事务处理类,实现 RocketMQLocalTransactionListener 接口,以及加上
@RocketMQTransactionListener 注解,这个类似方法的调用是异步的;
executeLocalTransaction 方法,当我们处理完业务后,可以根据业务处理情况,返回事务执行状
态,有 bollback , commit or unknown 三种,分别是回滚事务,提交事务和未知;根据事务消息执行
流程,如果返回bollback,则直接丢弃消息;如果是返回commit,则消费消息;如果是unknow,则继
续等待,然后调用checkLocalTransaction方法,最多重试15次,超过了默认丢弃此消息;
checkLocalTransaction 方法,是当MQ Server未得到MQ发送方应答,或者超时的情况,或者应答是
unknown的情况,调用此方法进行检查确认,返回值和上面的方法一样;
所以其实核心就是在executeLocalTransaction()方法中写好本地事务逻辑,如果异常就bollback。
如果因为网络问题迟迟不能确定消息, checkLocalTransaction ()方法就会帮我们回查,
RocketMQ过滤消息
RocketMQ提供了TAG和SQL表达式两种消息过滤方式
根据TAG方式过滤消息
消息发送端只能设置一个tag,消息接收端可以设置多个tag。
接收消息端通过 ‘||’ 设置多个tag,如下:tag1 || tag2 || tag3 || …
上实例,生产端发送三个消息,TAG分别是TAG1,TAG2,TAG3
/*** 发送带Tag消息,测试根据Tag过滤消息 */
public void sendMessageWithTag() {
// 构造消息1
Message msg1 = MessageBuilder.withPayload("rocketmq过滤消息测试-TAG01").build();
// 构造消息2
Message msg2 = MessageBuilder.withPayload("rocketmq过滤消息测试-TAG02").build();
// 构造消息3
Message msg3 = MessageBuilder.withPayload("rocketmq过滤消息测试-TAG03").build();
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq" + ":" + "TAG1", msg1);
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq" + ":" + "TAG2", msg2);
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq" + ":" + "TAG3", msg3);
}
消费端,通过selectorExpression = “TAG1 || TAG2”,selectorType = SelectorType.TAG,指定需要消
费的TAG
@RocketMQMessageListener(topic = "java1234-filter-rocketmq", consumerGroup = "${rocketmq.consumer.group}",
selectorExpression = "TAG1 || TAG2", selectorType = SelectorType.TAG)
@Component
public class ConsumerService implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("消费者:收到消息内容:" + s);
}
}
结果
根据SQL表达式过滤消息
SQL表达式方式可以根据发送消息时输入的属性进行一些计算。
RocketMQ的SQL表达式语法 只定义了一些基本的语法功能。
数字比较,如>,>=,<,<=,BETWEEN,=;
字符比较,如:=,<>,IN;
IS NULL or IS NOT NULL;
逻辑运算符:AND, OR, NOT;
常量类型:
数值,如:123, 3.1415;
字符, 如:‘abc’, 必须使用单引号; }@RocketMQMessageListener(topic = “java1234-filter-rocketmq”,consumerGroup =“${rocketmq.consumer.group}” ,selectorExpression = “TAG1 || TAG2”,selectorType = SelectorType.TAG) @Component public class ConsumerService implements RocketMQListener { @Override public void onMessage(String s) { System.out.println(“消费者:收到消息内容:”+s); } }
NULL,特殊常量
Boolean, TRUE or FALSE;
上实例,发送三个消息,分别带上不同的header头信息
/*** 发送SQL表达式头信息消息,测试根据SQL表达式过滤消息 */
public void sendMessageWithSQL() {
// 构造消息1
Message msg1 = MessageBuilder.withPayload("rocketmq过滤消息测试01").build();
Map<String, Object> headers = new HashMap<>();
headers.put("type", "pay");
headers.put("a", 10);
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq", msg1, headers);
// 构造消息2
Message msg2 = MessageBuilder.withPayload("rocketmq过滤消息测试02").build();
Map<String, Object> headers2 = new HashMap<>();
headers2.put("type", "store");
headers2.put("a", 4);
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq", msg2, headers2);
// 构造消息3
Message msg3 = MessageBuilder.withPayload("rocketmq过滤消息测试03").build();
Map<String, Object> headers3 = new HashMap<>();
headers3.put("type", "user");
headers3.put("a", 7);
rocketMQTemplate.convertAndSend("java1234-filter-rocketmq", msg3, headers3);
}
消费者端,selectorExpression = “type=‘user’ or a <7”,selectorType = SelectorType.SQL92 ,指定
selectorType 以及设置表达式selectorExpression
@RocketMQMessageListener(topic = "java1234-filter-rocketmq", consumerGroup = "${rocketmq.consumer.group}",
selectorExpression = "type='user' or a <7", selectorType = SelectorType.SQL92)
@Component
public class ConsumerService implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("消费者:收到消息内容:" + s);
}
}
默认不支持SQL表达式,启动报错
找到 broker.conf 配置文件
加上
enablePropertyFilter=true
重启borker即可