-
一、RocketMQ 使用方式
(一)依赖
在使用 RocketMQ 的 Java 项目中,通常需要添加以下 Maven 依赖:<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.9.3</version> </dependency>
请根据实际情况选择合适的 RocketMQ 版本。
(二)配置
-
NameServer 地址配置:
- 在生产者和消费者的代码中,都需要设置 NameServer 的地址,如示例代码中:
producer.setNamesrvAddr("localhost:9876"); consumer.setNamesrvAddr("localhost:9876");
这里将 NameServer 地址设置为
localhost:9876
,实际应用中需根据你的 NameServer 部署位置进行修改。可以是一个 IP 地址加端口的组合,也可以是多个 NameServer 地址的集合,多个地址之间用分号分隔,以提高系统的可用性,例如:producer.setNamesrvAddr("192.168.1.100:9876;192.168.1.101:9876");
这样生产者或消费者会尝试连接这些 NameServer 中的一个,若其中一个不可用,可连接其他的。
-
生产者配置:
- 生产者组名:在创建生产者实例时,需要指定生产者组名,如:
DefaultMQProducer producer = new DefaultMQProducer("producer - group");
生产者组名用于对生产者进行逻辑分组,方便管理和负载均衡等操作。不同生产者组可以有不同的消息发送策略或行为,可根据业务模块或功能划分生产者组。
- 消息发送方式配置:
生产者支持同步、异步和单向发送消息。
// 同步发送 SendResult sendResult = producer.send(message); // 异步发送 producer.send(message, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { // 消息发送成功后的处理逻辑 } @Override public void onException(Throwable e) { // 消息发送失败后的处理逻辑 } }); // 单向发送 producer.sendOneway(message);
同步发送需要等待接收方响应,适用于重要消息;异步发送可指定回调函数,在发送完成后执行相应操作,适用于对时间敏感场景;单向发送不等待回应,适用于对可靠性要求不高的场景。
- 消息属性配置:
除了主题和 Tag 外,消息可以设置更多属性,例如消息的键值对:
message.putUserProperty("key1", "value1");
这些属性可在消费者端根据需要获取,用于业务逻辑的进一步处理。
-
消费者配置:
- 消费者组名:创建消费者实例时指定消费者组名,如:
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer - group");
消费者组内的多个消费者会共同处理消息,在集群消费模式下,消息只会被组内一个消费者消费,避免重复消费;在广播消费模式下,组内所有消费者都能收到消息。
- 消息订阅配置:
可通过consumer.subscribe
方法订阅主题和 Tag,如:
consumer.subscribe("TopicTest", "TagA || TagB");
这里订阅了
TopicTest
主题,且包含TagA
或TagB
的消息,可根据业务需求灵活设置订阅条件。- 消费模式配置:
支持集群消费和广播消费,默认为集群消费,可通过以下方式设置为广播消费:
consumer.setMessageModel(MessageModel.BROADCAST);
- 消息监听器配置:
注册消息监听器,如示例代码中使用的MessageListenerConcurrently
是并发消费监听器,也可以使用MessageListenerOrderly
实现顺序消费,其consumeMessage
方法会确保同一队列的消息顺序消费:
consumer.registerMessageListener(new MessageListenerOrderly() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { // 顺序消费的处理逻辑 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } });
消费监听器处理接收到的消息,根据消费结果返回不同状态,如
CONSUME_SUCCESS
表示消费成功,其他状态会触发不同的重试机制。
二、RocketMQ 概念解释
(一)核心组件
- NameServer:
- 作为元数据管理中心,主要负责对元数据的管理,包括 Topic 和路由信息的管理。它由 Netty 实现,是无状态节点,提供路由注册、发现和管理服务。类似于 ZooKeeper,但有自身特点。
- 多个 NameServer 节点组成集群时,相互独立,无信息交互,属于伪集群,这增强了扩展性和稳定性。
- 主要开销在于维持心跳和提供 Topic - Broker 的对应关系,需要注意心跳数据量问题,若 Topic 过多可能导致心跳失败。
- 生产者和消费者通过向 NameServer 获取 Broker 的路由信息进行消息发送和拉取操作。
- Broker:
- 是消息的中转站,负责消息的收发和持久化,是 RocketMQ 的核心服务提供方。
- 与所有 NameServer 节点保持长连接和心跳,将 Topic 信息注册到 NameServer 并更新心跳时间。
- 提供消息的接收、存储和拉取等功能,支持主从架构(Master - Slave),Master 节点挂掉后,Consumer 可切换到 Slave 节点继续消费消息。
- Producer:
- 是消息的生产者,一般由业务系统产生消息。
- 与 NameServer 建立连接获取 Topic 路由信息,支持集群部署,可采用不同的消息发送方式(同步、异步、单向)。
- 不同发送方式适用于不同业务场景,如同步用于重要数据传输,异步用于时间敏感业务,单向用于可靠性要求不高的场景。
- Consumer:
- 是消息的消费者,由业务系统异步消费消息。
- 支持集群消费和广播消费模式,还支持 Push 和 Pull 两种消费模式,Push 是对 Pull 消费的封装,通过注册消费监听器来实现消息消费。
(二)核心概念
- Message:
- 消息实体,包含主题(topic)和 Tag 等信息,topic 是消息传输的通道地址,必须设置;Tag 可作为 topic 的子级别,用于更精细标识消息,可根据业务场景灵活设置或不设置。
- 消息发送方根据 topic 发送消息,消费方根据 topic 选择消费逻辑,Tag 可辅助查找和区分消息,方便业务逻辑的细化处理。
- Topic:
- 消息的主题,属于消息的第一级分类,多个生产者可向同一 Topic 发送消息,多个消费者可同时消费同一 Topic 的消息,实现了生产者和消费者的解耦。
- 例如在电商系统中,可将所有订单相关消息发送到同一 Topic,不同业务模块可根据需求订阅该 Topic 进行消息获取。
- Tag:
- 属于消息的第二级分类,可看作子主题,为消息提供更多灵活配置,辅助消息的标识和查找。
- 在同一业务模块中,可通过不同的 Tag 区分不同状态或类型的消息,例如订单业务中的不同订单状态。
- Queue 队列:
- 每个 Queue 内部是有序的,有读写队列之分,与常见读写分离机制不同,保障消息的有序处理和高效读写。
- 读写队列在数据存储和处理上有独特机制,为消息存储和处理提供了有序环境。
- Offset 偏移量:
- 用于定位消息队列中的消息,是 long 类型,可将消息队列看作无限长的数组,offset 是数组的下标。
- 通过 offset,消费者能准确找到消息队列中的消息进行消费,确保消息消费的准确性。
- Group 分组:
- 分为生产者组和消费者组,代表一类生产者和消费者,方便对消息的生产和消费进行统一管理和配置。
- 例如将处理同一业务的生产者或消费者分别划分为一个组,便于进行统一操作和资源分配。
三、RocketMQ 优缺点总结
(一)优点
- 单机吞吐量:单机可达十万级吞吐量,处理高并发消息能力强,适合大型系统。
- 可用性:分布式架构,部分节点故障不影响系统正常运行,保障业务连续性。
- 消息可靠性:合理配置可实现近乎 0 丢失,适用于对数据可靠性要求高的领域。
- 功能支持:功能完善,提供事务消息、顺序消息等多种特性,扩展性好,便于集群扩展。
- 消息堆积能力:支持 10 亿级消息堆积,高负载下性能稳定。
- 源码可定制性:基于 Java 开发,方便开发人员定制化开发,对 MQ 掌控度高。
- 场景适用性:专为金融互联网领域设计,在高并发场景下表现卓越,经过多次大型促销活动考验。
(二)缺点
- 客户端语言支持有限:目前仅支持 Java 及 C++ 客户端,且 C++ 客户端不成熟,限制多语言开发环境应用。
- 社区活跃度:相比热门开源项目,社区活跃度不高,获取支持和解决方案较慢。
- 接口兼容性:未实现 JMS 等标准接口,迁移时可能需修改大量代码,增加迁移成本。
四、RocketMQ 执行流程说明
- NameServer 启动:作为路由管理中心首先启动,为后续组件提供服务。
- Broker 注册:Broker 启动时向 NameServer 注册自身信息,包括地址和负责的 Topic 等。
- 生产者发送消息:生产者从 NameServer 获取 Broker 服务器地址列表,根据负载均衡算法选择 Broker 发送消息,避免单点压力过大。
- NameServer 与 Broker 心跳检测:NameServer 与 Broker 维持心跳机制,检测 Broker 是否存活,若宕机将其从路由表移除,确保路由信息准确。
- 消费者订阅消息:消费者从 NameServer 获取 Broker 地址列表,根据 Broker 配置决定订阅消息规则,可配置不同消费策略。
五、RocketMQ 中 Broker 故障处理机制
- Broker 与 NameServer 之间每隔 30s 进行心跳连接,NameServer 每隔 10s 检查 Broker 心跳时间,超过 120s 无心跳则认为 Broker 挂掉。
- 对于生产者,通过负载均衡算法避免向故障 Broker 发送消息,将消息改发到正常 Broker 上。
- 对于消费者,可从 Broker 的 Slave 节点拉取消息继续消费,保证系统可用性和数据连续性。
六、示例代码解释
(一)生产者代码
public class ProducerExample { public static void main(String[] args) throws Exception { // 创建一个生产者实例,并指定生产者组名 DefaultMQProducer producer = new DefaultMQProducer("producer - group"); // 设置NameServer地址 producer.setNamesrvAddr("localhost:9876"); // 启动生产者 producer.start(); for (int i = 0; i < 10; i++) { // 创建一条消息,指定主题、Tag和消息内容 Message message = new Message("TopicTest", "TagA", ("Hello RocketMQ " + i).getBytes()); // 同步发送消息 SendResult sendResult = producer.send(message); System.out.printf("%s%n", sendResult); } // 关闭生产者 producer.shutdown(); } }
这段代码实现了一个简单的 RocketMQ 生产者。首先导入相关类,创建
DefaultMQProducer
实例并指定生产者组名,设置 NameServer 地址,启动生产者。通过循环创建 10 条消息,指定主题和 Tag,使用同步发送方式发送消息,打印发送结果,最后关闭生产者。(二)消费者代码
public class ConsumerExample { public static void main(String[] args) throws Exception { // 创建一个消费者实例,并指定消费者组名 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer - group"); // 设置NameServer地址 consumer.setNamesrvAddr("localhost:9876"); // 订阅主题和Tag consumer.subscribe("TopicTest", "TagA"); // 注册消息监听器,用于处理接收到的消息 consumer.registerMessageListener(new MessageListenerConcurrently() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for (MessageExt msg : msgs) { System.out.println(new String(msg.getBody())); } // 返回消费成功状态 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // 启动消费者 consumer.start(); System.out.println("Consumer Started."); } }
该代码实现了一个简单的 RocketMQ 消费者。导入相关类后,创建
DefaultMQPushConsumer
实例,指定消费者组名,设置 NameServer 地址,订阅主题和 Tag,注册并发消息监听器处理消息,将消息内容打印输出,返回消费成功状态,最后启动消费者并输出启动信息。七、总结
RocketMQ 是一款由阿里巴巴自主研发的高性能消息中间件,具有分布式架构、高吞吐量、高可用性和高可靠性等诸多优点,在消息类型、功能支持和消息堆积能力上表现出色,尤其适用于金融、电商等对数据可靠性和高并发处理要求较高的领域。然而,它也存在一些局限性,如客户端语言支持不够丰富,社区活跃度相对较低,以及接口兼容性方面的问题。通过其核心组件(NameServer、Broker、Producer 和 Consumer)的协同工作,以及对核心概念(Message、Topic、Tag、Queue、Offset 和 Group)的巧妙运用,RocketMQ 能够实现高效的消息传输和处理。在实际使用中,开发者需要根据业务需求合理配置生产者和消费者,选择合适的消息发送和消费模式,同时要关注 NameServer 与 Broker 的心跳机制和故障处理,确保系统的稳定运行。示例代码展示了简单的生产者和消费者的实现,为开发人员提供了一个入门的参考,帮助他们更好地理解和使用 RocketMQ 进行消息的生产和消费操作。
-
RocketMQ原理、使用与实践指南
于 2025-01-13 15:48:58 首次发布