RocketMQ特性、专业术语(Producer,Producer Group,Consumer Group,Topic,Message,Tag,Broker,Name Server)等

本文介绍了RocketMQ的基础概念、核心组件及部署方式,并提供了简单的生产者和消费者示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

RocketMQ 是什么

Github 上关于 RocketMQ 的介绍: RcoketMQ 是一款低延迟、高可靠、可伸缩、易于使用的消息中间件。具有以下特性:

  1. 支持发布/订阅(Pub/Sub)和点对点(P2P)消息模型
  2. 在一个队列中可靠的先进先出(FIFO)和严格的顺序传递
  3. 支持拉(pull)和推(push)两种消息模式
  4. 单一队列百万消息的堆积能力
  5. 支持多种消息协议,如 JMS、MQTT 等
  6. 分布式高可用的部署架构,满足至少一次消息传递语义
  7. 提供 docker 镜像用于隔离测试和云集群部署
  8. 提供配置、指标和监控等功能丰富的 Dashboard

对于这些特性描述,大家简单过一眼就即可,深入学习之后自然就明白了。

专业术语

Producer

消息生产者,生产者的作用就是将消息发送到 MQ,生产者本身既可以产生消息,如读取文本信息等。也可以对外提供接口,由外部应用来调用接口,再由生产者将收到的消息发送到 MQ。

Producer Group

生产者组,简单来说就是多个发送同一类消息的生产者称之为一个生产者组。在这里可以不用关心,只要知道有这么一个概念即可。

Consumer

消息消费者,简单来说,消费 MQ 上的消息的应用程序就是消费者,至于消息是否进行逻辑处理,还是直接存储到数据库等取决于业务需要。

Consumer Group

消费者组,和生产者类似,消费同一类消息的多个 consumer 实例组成一个消费者组。

Topic

Topic 是一种消息的逻辑分类,比如说你有订单类的消息,也有库存类的消息,那么就需要进行分类,一个是订单 Topic 存放订单相关的消息,一个是库存 Topic 存储库存相关的消息。

Message

Message 是消息的载体。一个 Message 必须指定 topic,相当于寄信的地址。Message 还有一个可选的 tag 设置,以便消费端可以基于 tag 进行过滤消息。也可以添加额外的键值对,例如你需要一个业务 key 来查找 broker 上的消息,方便在开发过程中诊断问题。

Tag

标签可以被认为是对 Topic 进一步细化。一般在相同业务模块中通过引入标签来标记不同用途的消息。

Broker

Broker 是 RocketMQ 系统的主要角色,其实就是前面一直说的 MQ。Broker 接收来自生产者的消息,储存以及为消费者拉取消息的请求做好准备。

Name Server

Name Server 为 producer 和 consumer 提供路由信息。

RocketMQ 架构

RocketMQ 架构
RocketMQ 架构

由这张图可以看到有四个集群,分别是 NameServer 集群、Broker 集群、Producer 集群和 Consumer 集群:

  1. NameServer: 提供轻量级的服务发现和路由。 每个 NameServer 记录完整的路由信息,提供等效的读写服务,并支持快速存储扩展。
  2. Broker: 通过提供轻量级的 Topic 和 Queue 机制来处理消息存储,同时支持推(push)和拉(pull)模式以及主从结构的容错机制。
  3. Producer:生产者,产生消息的实例,拥有相同 Producer Group 的 Producer 组成一个集群。
  4. Consumer:消费者,接收消息进行消费的实例,拥有相同 Consumer Group 的 Consumer 组成一个集群。

简单说明一下图中箭头含义,从 Broker 开始,Broker Master1 和 Broker Slave1 是主从结构,它们之间会进行数据同步,即 Date Sync。同时每个 Broker 与 NameServer 集群中的所有节 点建立长连接,定时注册 Topic 信息到所有 NameServer 中。

Producer 与 NameServer 集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Broker Master 建立长连接,且定时向 Broker 发送心跳。Producer 只能将消息发送到 Broker master,但是 Consumer 则不一样,它同时和提供 Topic 服务的 Master 和 Slave 建立长连接,既可以从 Broker Master 订阅消息,也可以从 Broker Slave 订阅消息。

RocketMQ 集群部署模式

  1. 单 master 模式 也就是只有一个 master 节点,称不上是集群,一旦这个 master 节点宕机,那么整个服务就不可用,适合个人学习使用。
  2. 多 master 模式 多个 master 节点组成集群,单个 master 节点宕机或者重启对应用没有影响。 优点:所有模式中性能最高 缺点:单个 master 节点宕机期间,未被消费的消息在节点恢复之前不可用,消息的实时性就受到影响。 注意:使用同步刷盘可以保证消息不丢失,同时 Topic 相对应的 queue 应该分布在集群中各个节点,而不是只在某各节点上,否则,该节点宕机会对订阅该 topic 的应用造成影响。
  3. 多 master 多 slave 异步复制模式 在多 master 模式的基础上,每个 master 节点都有至少一个对应的 slave。master 节点可读可写,但是 slave 只能读不能写,类似于 mysql 的主备模式。 优点: 在 master 宕机时,消费者可以从 slave 读取消息,消息的实时性不会受影响,性能几乎和多 master 一样。 缺点:使用异步复制的同步方式有可能会有消息丢失的问题。
  4. 多 master 多 slave 同步双写模式 同多 master 多 slave 异步复制模式类似,区别在于 master 和 slave 之间的数据同步方式。 优点:同步双写的同步模式能保证数据不丢失。 缺点:发送单个消息 RT 会略长,性能相比异步复制低10%左右。 刷盘策略:同步刷盘和异步刷盘(指的是节点自身数据是同步还是异步存储) 同步方式:同步双写和异步复制(指的一组 master 和 slave 之间数据的同步) 注意:要保证数据可靠,需采用同步刷盘和同步双写的方式,但性能会较其他方式低。
  

RocketMQ 单主部署

鉴于是快速入门,我选择的是第一种单 master 的部署模式。先说明一下我的安装环境:

  1. Centos 7.2
  2. jdk 1.8
  3. Maven 3.2.x
  4. Git

这里 git 可用可不用,主要是用来直接下载 github 上的源码。也可以选择自己到 github 上下载,然后上传到服务器上。以git操作为示例。

  1. clone 源码并用 maven 编译
> git clone https://github.com/alibaba/RocketMQ.git /opt/RocketMQ
> cd /opt/RocketMQ && mvn -Dmaven.test.skip=true clean package install assembly:assembly -U
> cd target/alibaba-rocketmq-broker/alibaba-rocketmq

此处可能遇到的问题
一、执行"git clone https://github.com/alibaba/RocketMQ.git /home/inspkgs/RocketMQ"时出现以下提示:

fatal: unable to access 'https://github.com/alibaba/RocketMQ.git/': Could not resolve host: github.com; Unknown error

解决办法:一般是由于网络原因造成的,执行以下命令

> ping github.com

确定可以 ping 通之后,再重新执行 git clone 命令。
二、执行"mvn -Dmaven.test.skip=true clean package install assembly:assembly -U"编译时,可能出现下载相关jar很慢的情况。
这也是由于默认 maven 中央仓库在国外的原因,可以根据需要在 /home/maven/conf/setting.xml 中的 <mirrors></mirrors> 添加以下内容后重新编译:

<mirror>
    <id>aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
  1. 启动 Name Server
> nohup sh /opt/RocketMQ/bin/mqnamesrv &
//执行 jps 查看进程
> jps
25913 NamesrvStartup
//查看日志确保服务已正常启动
> tail -f ~/logs/rocketmqlogs/namesrv.log
The Name Server boot success...
  1. 启动 broker
> nohup sh /opt/RocketMQ/bin/mqbroker -n localhost:9876 &
//执行 jps 查看进程
> jps
25954 BrokerStartup
//查看日志确保服务已正常启动
> tail -f ~/logs/rocketmqlogs/broker.log 
The broker[broker-a, 10.1.54.121:10911] boot success...
  1. 发送和接收消息
    发送/接收消息之前,我们需要告诉客户端 NameServer 地址。RocketMQ 提供了多种方式来实现这一目标。为简单起见,我们使用环境变量 NAMESRV_ADDR。
> export NAMESRV_ADDR=localhost:9876
> sh /opt/RocketMQ/bin/tools.sh com.alibaba.rocketmq.example.quickstart.Producer
SendResult [sendStatus=SEND_OK, msgId= ...
> sh /opt/RocketMQ/bin/tools.sh com.alibaba.rocketmq.example.quickstart.Consumer
ConsumeMessageThread_%d Receive New Messages: [MessageExt...
  1. 关闭服务
> sh /opt/RocketMQ/bin/mqshutdown broker
The mqbroker(36695) is running...
Send shutdown request to mqbroker(36695) OK
> sh /opt/RocketMQ/bin/mqshutdown namesrv
The mqnamesrv(36664) is running...
Send shutdown request to mqnamesrv(36664) OK

生产者、消费者 Demo

  1. 生产者
public class Producer {
    public static void main(String[] args) throws MQClientException, InterruptedException {

        //声明并初始化一个producer
        //需要一个producer group名字作为构造方法的参数,这里为producer1
        DefaultMQProducer producer = new DefaultMQProducer("producer1");
        
        //设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
        //NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
        producer.setNamesrvAddr("10.1.54.121:9876;10.1.54.122:9876");
        
        //调用start()方法启动一个producer实例
        producer.start();

        //发送10条消息到Topic为TopicTest,tag为TagA,消息内容为“Hello RocketMQ”拼接上i的值
        for (int i = 0; i < 10; i++) {
            try {
                Message msg = new Message("TopicTest",// topic
                        "TagA",// tag
                        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)// body
                );
                
                //调用producer的send()方法发送消息
                //这里调用的是同步的方式,所以会有返回结果
                SendResult sendResult = producer.send(msg);
                
                //打印返回结果,可以看到消息发送的状态以及一些相关信息
                System.out.println(sendResult);
            } catch (Exception e) {
                e.printStackTrace();
                Thread.sleep(1000);
            }
        }

        //发送完消息之后,调用shutdown()方法关闭producer
        producer.shutdown();
    }
}
  1. 消费者
public class Consumer {

    public static void main(String[] args) throws InterruptedException, MQClientException {
    
        //声明并初始化一个consumer
        //需要一个consumer group名字作为构造方法的参数,这里为consumer1
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer1");

        //同样也要设置NameServer地址
        consumer.setNamesrvAddr("10.1.54.121:9876;10.1.54.122:9876");

        //这里设置的是一个consumer的消费策略
        //CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
        //CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
        //CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        //设置consumer所订阅的Topic和Tag,*代表全部的Tag
        consumer.subscribe("TopicTest", "*");

        //设置一个Listener,主要进行消息的逻辑处理
        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {

                System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs);
                
                //返回消费状态
                //CONSUME_SUCCESS 消费成功
                //RECONSUME_LATER 消费失败,需要稍后重新消费
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        //调用start()方法启动consumer
        consumer.start();

        System.out.println("Consumer Started.");
    }
}



作者:冯先生的笔记
链接:http://www.jianshu.com/p/824066d70da8
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:冯先生的笔记链接:http://www.jianshu.com/p/824066d70da8來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
<think>首先,用户的问题是如何在RocketMQ中发送带tag的消息以及接收这些消息。我需要基于提供的引用内容来构建回答。 从引用中提取关键信息: - 引用[1]:展示了发送带tag消息的Java代码示例。使用`rocketMQTemplate.convertAndSend("say-msg:shop", msg);`,其中"say-msg:shop"表示topic为"say-msg",tag为"shop"。 - 引用[2]:解释了使用tag的原因,即通过tag过滤消息,实现不同业务场景的消息区分。 - 引用[3]:提到RocketMQ的部署和基本概念,包括消息发送和接收。 - 引用[4]:展示了单向发送消息的Java代码,包括创建消息对象`Message`,指定topictags、keys等。 用户需求明确:发送带tag的消息和接收这些消息。我需要提供清晰的步骤和代码示例。 回答结构: 1. **介绍tag的作用**:解释为什么需要tag,基于引用[2],tag用于消息过滤,帮助消费者区分不同业务的消息。 2. **发送带tag的消息**: - 使用Spring Boot的`RocketMQTemplate`(如引用[1])。 - 或者使用原生Java API(如引用[4])。 3. **接收带tag的消息**: - 消费者端如何订阅带tag的消息。 4. **代码示例**: - 发送端:展示如何发送带tag的消息。 - 接收端:展示如何接收带特定tag的消息。 5. **注意事项**:如tag的格式、消费者订阅规则。 6. **生成相关问题**:基于回答内容,提出相关问题。 确保LaTeX格式正确: - 行内数学表达式用$...$,但在这个上下文中,可能不需要数学表达式。主题是RocketMQ,所以可能没有数学内容。如果需要,我会应用。 - 独立公式用$$...$$,但这里可能不适用。 - 使用中文回答。 生成相关问题: - 在回答末尾,添加相关问题,如示例所示。 参考引用: - 在回答中,引用相关部分,末尾添加引用标识如[^1]。 完整回答结构: 1. **引言**:简要介绍RocketMQtag的作用。 2. **发送带tag的消息**: - 使用RocketMQTemplate(Spring Boot)。 - 使用原生Java API。 3. **接收带tag的消息**: - 消费者订阅方式。 4. **完整示例**:一个简单的发送和接收代码。 5. **注意事项**。 6. **相关问题**。 基于引用: - 发送:引用[1]和[4]。 - 接收:引用[3]提到消费者模式,但需要具体化。引用[4]有消费者部分,但未显示tag过滤。我需要推断:消费者订阅时指定tag。 消费者端:在订阅时,使用`DefaultMQPushConsumer`,设置topictag。例如:`consumer.subscribe("topic", "tag1 || tag2")`。 代码示例: - 发送:使用`RocketMQTemplate`或`DefaultMQProducer`。 - 接收:使用`DefaultMQPushConsumer`。 确保回答真实可靠:基于提供的引用和标准RocketMQ知识。</think>### RocketMQ 中发送和接收带 Tag 的消息 在 RocketMQ 中,Tag 是一种消息过滤机制,用于区分同一 Topic 下的不同业务消息。例如,发送带 Tag 的消息可以让消费者只接收特定 Tag 的消息,提高消息处理的效率和准确性[^2]。以下我将逐步解释如何发送和接收带 Tag 的消息,包括代码示例和注意事项。回答基于 RocketMQ 的 Java API 实现(版本 4.x),并参考了标准实践。 #### 1. Tag 的作用和背景 - **为什么使用 Tag?** RocketMQTopic 用于分类消息,但同一 Topic 下可能包含多种业务类型。Tag 作为子分类,允许消费者通过表达式(如 `tagA` 或 `tagA || tagB`)过滤消息。例如: - 电商场景:Topic 为 `order`,Tag 为 `pay` 的消息表示支付成功,Tag 为 `cancel` 表示订单取消[^2]。 - 优势:减少不必要消息传输,提升消费者性能[^3]。 #### 2. 发送带 Tag 的消息 发送消息时,需在消息体中指定 TagRocketMQ 提供两种主要方式:**Spring Boot 集成**(推荐)和**原生 Java API**。 - **方式一:使用 Spring Boot 的 `RocketMQTemplate`(简化版)** 适用于 Spring Boot 项目。示例代码: ```java import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController public class ProducerController { @Autowired private RocketMQTemplate rocketMQTemplate; /** * 发送带 Tag 的消息 * @param msg 消息内容 * @return 发送结果 * Topic: "order", Tag: "pay" */ @GetMapping("/send/{msg}") public String sendMsgWithTag(@PathVariable String msg) { // 格式: "topic:tag" rocketMQTemplate.convertAndSend("order:pay", msg); return "消息发送成功: " + msg; } } ``` - **说明**: - `convertAndSend("order:pay", msg)` 中,`order` 是 Topic,`pay` 是 Tag。消息会被发送到 Topic `order`,但消费者可通过 Tag `pay` 过滤[^1]。 - 优点:代码简洁,适合快速集成。 - **方式二:使用原生 Java API(`DefaultMQProducer`)** 适用于非 Spring 项目。示例代码: ```java import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message; public class NativeProducer { public static void main(String[] args) throws Exception { // 创建生产者实例 DefaultMQProducer producer = new DefaultMQProducer("producer_group"); producer.setNamesrvAddr("localhost:9876"); // NameServer 地址 producer.start(); // 创建消息:指定 TopicTag 和内容 String topic = "order"; String tag = "pay"; // Tag 名称 String body = "订单支付成功"; Message msg = new Message(topic, tag, body.getBytes()); // 发送消息 producer.send(msg); System.out.println("消息发送成功: " + body); // 关闭生产者 producer.shutdown(); } } ``` - **说明**: - `new Message(topic, tag, body.getBytes())` 明确设置 Tag。`send()` 方法支持同步、异步或单向发送(单向发送不关心结果,适合日志场景)[^4]。 - 确保 NameServer 地址正确(例如 `localhost:9876`),否则消息发送失败[^3]。 #### 3. 接收带 Tag 的消息 消费者通过订阅 TopicTag 表达式来接收消息。RocketMQ 支持两种消费模式:**集群模式**(默认,消息被多个消费者分摊)和**广播模式**(所有消费者接收全部消息)[^3]。 - **消费者示例代码(使用 `DefaultMQPushConsumer`)** ```java import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.common.message.MessageExt; public class TagConsumer { public static void main(String[] args) throws Exception { // 创建消费者实例 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group"); consumer.setNamesrvAddr("localhost:9876"); // NameServer 地址 // 订阅 TopicTag 表达式(支持通配符 * 或逻辑 ||) consumer.subscribe("order", "pay"); // 只接收 Tag 为 "pay" 的消息 // 例如:consumer.subscribe("order", "pay || cancel") 接收多个 Tag // 注册消息监听器 consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> { for (MessageExt msg : msgs) { System.out.println("收到消息: " + new String(msg.getBody())); System.out.println("Tag: " + msg.getTags()); // 获取消息的 Tag } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; // 确认消费成功 }); // 启动消费者 consumer.start(); System.out.println("消费者已启动,等待消息..."); } } ``` - **说明**: - `consumer.subscribe("order", "pay")` 指定只接收 Topic `order` 下 Tag 为 `pay` 的消息。表达式可以是 `*`(所有 Tag)或 `tagA || tagB`(多个 Tag)[^2]。 - `msg.getTags()` 可获取消息的 Tag,用于业务逻辑处理。 - 消费者组名(`consumer_group`)需唯一,避免重复消费。 #### 4. 注意事项 - **Tag 命名规范**: - Tag 必须是字符串,长度不超过 128 字符。避免特殊字符(如 `:`),推荐使用字母数字。 - 在订阅表达式中,Tag 区分大小写。 - **性能优化**: - 发送端:批量发送消息减少网络开销。 - 接收端:使用集群模式分摊负载,避免消息积压(参考 RocketMQ 的并发消费机制)[^3]。 - **错误处理**: - 发送失败时,检查 NameServer 状态和网络连接。 - 消费失败时,实现重试机制(例如,返回 `RECONSUME_LATER`)。 - **依赖管理**: 确保项目中添加 RocketMQ 依赖(Maven 示例): ```xml <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.2.3</version> <!-- 使用最新版本 --> </dependency> ``` #### 5. 完整流程示例 假设一个订单系统: - **生产者**:发送 Topic 为 `order`,Tag 为 `pay` 的消息。 - **消费者**:订阅 `order` 和 `pay`,处理支付成功逻辑。 运行步骤: 1. 启动 RocketMQ NameServerBroker(参考引用[^3]部署)。 2. 运行生产者代码发送消息。 3. 运行消费者代码接收并打印消息。 通过以上步骤,您可以高效实现带 Tag 的消息发送和接收。如果需要更高级功能(如顺序消息或事务消息),可扩展订阅表达式或使用 RocketMQ 的其他 API[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值