简介:RocketMQ是一款由阿里巴巴开源的高吞吐量、低延迟、高可用性消息中间件。本课程设计项目经过测试,旨在帮助学生掌握RocketMQ的原理、架构和实战应用。通过实践任务,学生将学习如何使用RocketMQ的API进行消息发送、接收和事务处理。本项目涵盖了各种使用场景,如点对点通信、发布/订阅模式和分布式事务,为学生在实际项目中应用RocketMQ打下坚实基础。
1. RocketMQ 简介
RocketMQ 是阿里巴巴开源的一个分布式消息队列中间件,它具有高性能、高可靠、高可用等特点,广泛应用于电商、金融、物流等领域。RocketMQ 采用 Master-Slave 架构,由 Name Server、Broker、Producer 和 Consumer 组成,提供了可靠的消息存储、灵活的消息路由和丰富的消息协议支持。
2.1 RocketMQ 的整体架构
2.1.1 生产者、消费者和 Broker
RocketMQ 的架构由以下三个核心组件组成:
- 生产者 (Producer) :负责将消息发送到 RocketMQ 集群。
- 消费者 (Consumer) :负责从 RocketMQ 集群接收消息。
- Broker :负责存储和转发消息。
2.1.2 Name Server
Name Server 是一个轻量级的组件,负责管理 Broker 的地址信息。生产者和消费者在启动时,会向 Name Server 注册,以获取 Broker 的地址。
2.1.3 Topic 和 Queue
Topic 是一个逻辑概念,代表一类消息。 Queue 是一个物理概念,代表一个存储消息的有序集合。每个 Topic 可以包含多个 Queue,每个 Queue 只能属于一个 Topic。
生产者将消息发送到 Topic,Name Server 会根据 Topic 路由消息到特定的 Broker。Broker 会将消息存储在相应的 Queue 中。消费者订阅 Topic,并从 Queue 中拉取消息。
代码示例:
// 创建一个生产者
Producer producer = DefaultMQProducer.createDefaultMQProducer();
// 设置 Name Server 地址
producer.setNamesrvAddr("127.0.0.1:9876");
// 创建一个 Topic
String topic = "TopicTest";
// 创建一个消息
Message message = new Message(topic, "Hello RocketMQ".getBytes());
// 发送消息
producer.send(message);
// 关闭生产者
producer.shutdown();
逻辑分析:
这段代码展示了如何使用生产者 API 发送消息到 RocketMQ。首先,创建一个生产者对象并设置 Name Server 地址。然后,创建一个 Topic 和一条消息。最后,使用生产者发送消息到 Topic。
参数说明:
-
DefaultMQProducer.createDefaultMQProducer()
:创建一个默认的生产者对象。 -
producer.setNamesrvAddr()
:设置 Name Server 地址。 -
new Message()
:创建一个消息对象。 -
producer.send()
:发送消息到 Topic。
3. RocketMQ API 使用
3.1 生产者 API
RocketMQ 提供了丰富的生产者 API,用于发送消息。
3.1.1 消息发送
public SendResult send(Message msg);
参数说明:
-
msg
: 要发送的消息对象
代码逻辑分析:
该方法将消息发送到 Broker。如果发送成功,则返回一个 SendResult
对象,其中包含消息 ID 和发送状态。
3.1.2 消息批量发送
public SendResult send(List<Message> msgs);
参数说明:
-
msgs
: 要批量发送的消息列表
代码逻辑分析:
该方法将一批消息发送到 Broker。如果发送成功,则返回一个 SendResult
对象,其中包含批量发送的消息 ID 和发送状态。
3.1.3 消息顺序发送
RocketMQ 支持消息顺序发送,保证同一业务主键的消息按顺序发送和接收。
public SendResult sendOrdered(Message msg, String shardingKey);
参数说明:
-
msg
: 要发送的消息对象 -
shardingKey
: 分片键,用于确定消息的顺序
代码逻辑分析:
该方法将消息发送到 Broker,并根据 shardingKey
将消息路由到特定的队列。这样,同一 shardingKey
的消息将按顺序发送和接收。
3.2 消费者 API
RocketMQ 也提供了丰富的消费者 API,用于接收消息。
3.2.1 消息接收
public ConsumeResult consume(MessageSelector selector, MessageListener listener);
参数说明:
-
selector
: 消息选择器,用于过滤要接收的消息 -
listener
: 消息监听器,用于处理接收到的消息
代码逻辑分析:
该方法启动一个消费者,并根据 selector
过滤要接收的消息。当有符合条件的消息到达时, listener
将被调用来处理消息。
3.2.2 消息批量接收
public ConsumeResult consume(MessageSelector selector, MessageListener listener, int maxMsgs);
参数说明:
-
selector
: 消息选择器,用于过滤要接收的消息 -
listener
: 消息监听器,用于处理接收到的消息 -
maxMsgs
: 每次批量接收的最大消息数
代码逻辑分析:
该方法类似于 consume
方法,但它一次批量接收指定数量的消息。
3.2.3 消息顺序接收
RocketMQ 支持消息顺序接收,保证同一业务主键的消息按顺序发送和接收。
public ConsumeResult consumeOrdered(MessageSelector selector, MessageListenerOrderly listener);
参数说明:
-
selector
: 消息选择器,用于过滤要接收的消息 -
listener
: 有序消息监听器,用于处理接收到的消息
代码逻辑分析:
该方法启动一个有序消费者,并根据 selector
过滤要接收的消息。当有符合条件的消息到达时, listener
将被调用来处理消息。有序消费者保证同一 shardingKey
的消息按顺序接收。
4. RocketMQ 消息发送与接收
4.1 消息发送流程
消息发送流程主要包括以下几个步骤:
4.1.1 生产者发送消息
生产者通过 send()
方法发送消息,该方法会将消息序列化为字节数组,然后发送到 Broker。
public SendResult send(Message message) {
// ...
}
4.1.2 Broker 接收消息
Broker 接收消息后,会将消息写入 Commit Log
,并生成一个 Offset
。
public AppendMessageResult appendMessage(MessageExtBrokerInner msg) {
// ...
}
4.1.3 Name Server 路由消息
生产者在发送消息时,需要指定 Topic
,Name Server 根据 Topic
将消息路由到对应的 Broker。
public List<String> queryBrokerAddrByTopic(String topic) {
// ...
}
4.2 消息接收流程
消息接收流程主要包括以下几个步骤:
4.2.1 消费者订阅消息
消费者通过 subscribe()
方法订阅消息,该方法会向 Name Server 注册订阅关系。
public void subscribe(String topic, String subExpression) {
// ...
}
4.2.2 消费者拉取消息
消费者通过 pull()
方法拉取消息,该方法会从 Broker 拉取指定数量的消息。
public PullResult pull(PullRequest pullRequest) {
// ...
}
4.2.3 消费者消费消息
消费者消费消息后,需要调用 ack()
方法确认消费成功。
public AckResult ack(AckMessageContext context) {
// ...
}
5. RocketMQ 实战项目
5.1 日志收集系统
5.1.1 系统设计
日志收集系统主要由以下组件组成:
- 日志产生端: 负责产生日志消息的应用程序或服务。
- 日志收集器: 负责收集日志消息并将其发送到 RocketMQ 集群。
- RocketMQ 集群: 负责存储和转发日志消息。
- 日志分析平台: 负责从 RocketMQ 集群中消费日志消息并进行分析。
5.1.2 代码实现
日志产生端代码:
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;
public class LogProducer {
public static void main(String[] args) throws Exception {
// 创建生产者
DefaultMQProducer producer = new DefaultMQProducer("log-producer");
// 设置 Name Server 地址
producer.setNamesrvAddr("127.0.0.1:9876");
// 启动生产者
producer.start();
// 创建消息
Message message = new Message("log-topic", "log-tag", "log message".getBytes());
// 发送消息
SendResult sendResult = producer.send(message);
System.out.println("发送日志消息成功,消息 ID:" + sendResult.getMsgId());
// 关闭生产者
producer.shutdown();
}
}
日志收集器代码:
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.common.message.MessageExt;
import java.util.List;
public class LogConsumer {
public static void main(String[] args) throws Exception {
// 创建消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("log-consumer");
// 设置 Name Server 地址
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅主题
consumer.subscribe("log-topic", "*");
// 注册消息监听器
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) {
for (MessageExt message : messages) {
System.out.println("收到日志消息:" + new String(message.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 启动消费者
consumer.start();
}
}
简介:RocketMQ是一款由阿里巴巴开源的高吞吐量、低延迟、高可用性消息中间件。本课程设计项目经过测试,旨在帮助学生掌握RocketMQ的原理、架构和实战应用。通过实践任务,学生将学习如何使用RocketMQ的API进行消息发送、接收和事务处理。本项目涵盖了各种使用场景,如点对点通信、发布/订阅模式和分布式事务,为学生在实际项目中应用RocketMQ打下坚实基础。