本文详细介绍了RocketMQ的基本概念、安装步骤以及消息模型,并通过手写RocketMQ项目实战,深入讲解了生产者与消费者的基本用法,包括消息的发送、接收和高级特性,帮助读者全面掌握RocketMQ的使用方法。手写RocketMQ项目实战涵盖了从创建生产者和消费者到发送和接收消息的全过程,同时提供了详细的代码示例和实战案例。
RocketMQ简介与安装 RocketMQ是什么RocketMQ是由阿里云开源的一个高性能分布式消息中间件,广泛应用于阿里巴巴集团内部的业务场景以及外部企业。RocketMQ主要用于解耦系统设计中的松耦合架构,允许系统之间异步通信,从而提高系统的可扩展性和稳定性。RocketMQ具有高并发、低延迟、高可用等特点,支持多种消息模型,可以满足不同场景下的需求。
RocketMQ的特点与优势- 高性能:RocketMQ采用了一系列高性能设计,如零拷贝技术、大内存页支持等,确保高吞吐量和低延迟。
- 高可用性:RocketMQ通过多Master多Slave集群模式实现消息的高可用性,避免单点故障。
- 消息可靠性:RocketMQ支持事务消息和顺序消息,确保消息的可靠传输。
- 灵活的消息路由:RocketMQ支持多种路由策略,如广播、集群等,可以根据业务需求灵活配置。
- 消息过滤与重试:RocketMQ支持多种消息过滤策略,如Tag、SQL过滤等,同时提供消息重试机制,确保消息的正确处理。
- 监控与管理:RocketMQ提供了完善的监控体系,可以实时监控集群状态,方便运维人员进行故障排查。
-
下载RocketMQ:访问RocketMQ的GitHub仓库,下载最新版本的RocketMQ。
-
解压RocketMQ:
tar -xvf rocketmq-all-4.9.2-bin-release.zip cd rocketmq-all-4.9.2-bin-release
-
安装JDK:确保系统已经安装了Java JDK环境,并配置好环境变量。假设JDK版本为1.8,可以使用以下命令进行安装:
sudo apt-get update sudo apt-get install openjdk-8-jdk
-
启动NameServer:NameServer是RocketMQ集群中的消息路由中心,用于存储和管理Broker的信息。
nohup sh bin/mqnamesrv &
-
启动Broker:Broker是RocketMQ集群中的消息存储中心,负责接收和存储生产者发送的消息,并将消息推送给消费者。
nohup sh bin/mqbroker -n 127.0.0.1:9876 &
- 验证安装:可以通过浏览器访问http://localhost:9876/来查看NameServer的状态,如果显示正常,说明RocketMQ已经安装成功。
RocketMQ支持多种消息模型,包括单向消息、同步消息和异步消息。单向消息模型中,生产者发送消息后不等待响应;同步消息模型中,生产者发送消息后等待响应,只有在收到确认消息后才认为消息发送成功;异步消息模型中,生产者发送消息后通过回调函数异步接收确认消息。
名称服务器(Naming Server)名称服务器(Name Server)是RocketMQ集群中的消息路由中心,用于存储和管理Broker的信息。当生产者或消费者启动时,它们会连接到Name Server,获取Broker的地址信息,从而实现消息的路由。Name Server提供了一个简单的HTTP接口用于获取Broker的信息,生产者和消费者可以通过该接口获取到需要连接的Broker地址。
消息队列(Broker)消息队列(Broker)是RocketMQ集群中的消息存储中心,负责接收和存储生产者发送的消息,并将消息推送给消费者。在RocketMQ中,Broker分为两种类型:Master和Slave。Master负责接收消息并将其存储到本地文件系统中,Slave则从Master同步数据,实现数据的冗余备份。在集群模式下,Master负责向Slave同步消息,实现消息的高可用性。
消费者(Consumer)消费者(Consumer)是消息的接收方,负责从Broker中接收并处理消息。RocketMQ支持两种类型的消费者:集群模式(Cluster)和广播模式(Broadcast)。集群模式下,消息只会被集群中的一个消费者处理,保证消息的正确性;广播模式下,消息会被所有消费者处理,保证消息的可靠性。
生产者(Producer)生产者(Producer)是消息的发送方,负责将消息发送到Broker中。RocketMQ支持多种类型的消息发送策略,包括同步发送(Sync)、异步发送(Async)和单向发送(OneWay)。同步发送模式下,生产者发送消息后等待响应,只有在收到确认消息后才认为消息发送成功;异步发送模式下,生产者发送消息后通过回调函数异步接收确认消息;单向发送模式下,生产者发送消息后不等待响应,直接返回。
手写RocketMQ生产者与消费者 创建生产者RocketMQ生产者的主要职责是创建消息并将其发送到指定的Topic。首先,生产者需要创建一个DefaultMQProducer实例,设置Producer Group名称,然后调用Start方法启动生产者。
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
public class Producer {
public static void main(String[] args) throws Exception {
// 创建一个生产者实例
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
// 设置Name Server地址
producer.setNamesrvAddr("localhost:9876");
// 启动生产者
producer.start();
// 创建一个消息
Message msg = new Message("TopicTest", // Topic
"TagA", // Tag
("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
// 发送消息
producer.send(msg);
// 关闭生产者
producer.shutdown();
}
}
创建生产者的主要步骤如下:
- 创建DefaultMQProducer实例。
- 设置Producer Group名称。
- 设置Name Server地址。
- 启动生产者。
- 创建消息,并设置消息的Topic、Tag、Body和Timeout。
- 发送消息。
- 关闭生产者。
RocketMQ消费者的职责是接收并处理来自指定Topic的消息。首先,消费者需要创建一个DefaultMQPushConsumer实例,设置Consumer Group名称,并订阅相应Topic的主题。然后调用Start方法启动消费者。
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
public class Consumer {
public static void main(String[] args) throws Exception {
// 创建一个消费者实例
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
// 设置Name Server地址
consumer.setNamesrvAddr("localhost:9876");
// 订阅主题
consumer.subscribe("TopicTest", "*");
// 设置消费模式为顺序消费
consumer.setMessageModel(MessageModel.BROADCASTING);
// 设置从队列头部开始消费
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
// 注册消息监听器
consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
for (MessageExt msg : msgs) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), new String(msg.getBody()));
}
// 返回消费状态
return ConsumeOrderlyStatus.SUCCESS;
});
// 启动消费者
consumer.start();
}
}
创建消费者的主要步骤如下:
- 创建DefaultMQPushConsumer实例。
- 设置Consumer Group名称。
- 设置Name Server地址。
- 订阅主题。
- 设置消费模式。
- 设置从队列头部开始消费。
- 注册消息监听器。
- 启动消费者。
生产者和消费者启动后,生产者可以开始发送消息,消费者可以接收并处理消息。生产者发送的消息会被Broker存储,当消费者连接到Broker时,Broker会根据消息的路由信息将消息推送给消费者。消费者接收到消息后,会调用消息监听器处理消息。
消息发送与接收的高级特性 消息的顺序发送与接收RocketMQ支持顺序消息的发送与接收,可以确保消息按照一定的顺序被生产和消费。通过设置消息的键(Key)来指定消息的顺序,并设置消息消费模式为ORDERLY来实现顺序消费。以下是一个简单的示例:
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("localhost:9876");
producer.start();
for (int i = 0; i < 10; i++) {
Message msg = new Message("TopicTest", // Topic
"TagA", // Tag
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET), // body
i); // key
producer.send(msg);
}
producer.shutdown();
}
}
public class Consumer {
public static void main(String[] args) throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TopicTest", "*");
consumer.setMessageModel(MessageModel.ORDERLY);
consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
for (MessageExt msg : msgs) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), new String(msg.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
});
consumer.start();
}
}
顺序发送与接收适用于需要保证消息顺序的场景,例如订单处理流程。
消息的延迟发送RocketMQ支持延迟消息的发送,可以通过设置消息的延迟级别来实现。RocketMQ提供了7个级别的延迟,分别是1秒、5秒、10秒、30秒、1分钟、2分钟、3分钟。在发送消息时,可以通过设置Message的DelayTimeLevel属性来指定延迟时间。
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("localhost:9876");
producer.start();
Message msg = new Message("TopicTest", // Topic
"TagA", // Tag
("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
msg.setDelayTimeLevel(1); // 设置延迟级别为1(1秒)
producer.send(msg);
producer.shutdown();
}
}
延迟发送适用于需要延迟一定时间后处理消息的场景,例如定时任务或者定时通知。
消息的事务处理RocketMQ支持事务消息的发送与接收,可以确保消息的一致性。在发送事务消息时,生产者需要先将消息发送到Broker,然后执行本地事务。如果本地事务执行成功,则向Broker发送确认消息,Broker会将消息推送给消费者;如果本地事务执行失败,则向Broker发送回滚消息,Broker不会将消息推送给消费者。
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.TransactionSendResult;
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("localhost:9876");
producer.setTransactionCheckListener(new TransactionCheckListener() {
@Override
public LocalTransactionState checkLocalTranscationState(String tranMsgId) {
// 根据tranMsgId查询本地事务状态
return LocalTransactionState.COMMIT_MESSAGE;
}
});
producer.start();
TransactionMQProducerImpl transactionMQProducer = (TransactionMQProducerImpl) producer;
transactionMQProducer.setLocalTransactionExecuter(new LocalTransactionExecuter() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 执行本地事务
return LocalTransactionState.UNKNOW;
}
});
TransactionSendResult result = producer.send(new Message("TopicTest", // Topic
"TagA", // Tag
("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000)); // timeout
System.out.printf("%s %s %n", result.getLocalTransactionState(), result.getMsgId());
producer.shutdown();
}
}
事务处理适用于需要确保消息可靠传输的场景,例如金融交易或其他重要的业务逻辑。
异常处理与故障排除 常见错误及其解决方案- 无法连接到Name Server:检查Name Server是否启动,Name Server地址是否正确。
- 无法连接到Broker:检查Broker是否启动,Broker地址是否正确。
- 消息发送失败:检查生产者是否配置正确,消息体是否为空。
- 消息接收失败:检查消费者是否配置正确,消费者组是否冲突。
- 消息丢失:检查Broker是否正常运行,是否配置了消息重试机制。
- 消息重复:检查生产者和消费者的消费模式是否一致,是否配置了消息去重机制。
RocketMQ提供了丰富的日志和监控功能,可以帮助运维人员及时发现和处理问题。RocketMQ的日志主要包括Name Server日志、Broker日志和Client日志。Name Server日志记录了Name Server的启动、停止和运行状态;Broker日志记录了Broker的启动、停止和运行状态,以及消息的接收、存储和推送状态;Client日志记录了生产者和消费者的启动、停止和运行状态,以及消息的发送和接收状态。
// 查看Name Server日志
tail -f ~/rocketmq/logs/NameServer/log.2023-01-01
// 查看Broker日志
tail -f ~/rocketmq/logs/Broker/log.2023-01-01
// 查看Client日志
tail -f ~/rocketmq/logs/Client/log.2023-01-01
RocketMQ提供了Rocketmq-console工具,可以帮助运维人员实时监控RocketMQ集群的状态。Rocketmq-console是一个Web应用,可以通过浏览器访问Rocketmq-console的Web界面,查看RocketMQ集群的运行状态、性能指标和报警信息。
// 启动Rocketmq-console
nohup java -jar rocketmq-console.jar --server.port=8080 --rocketmq.config.namesrvAddr=localhost:9876 &
// 访问Rocketmq-console
http://localhost:8080
消息丢失与重复处理
RocketMQ支持消息重试机制,可以在生产者和消费者端配置消息重试次数和重试间隔时间,确保消息的可靠传输。消息重试机制可以有效地解决消息丢失和重复的问题。
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("localhost:9876");
producer.setRetryTimesWhenSendFailed(5); // 设置重试次数为5
producer.setSendMsgTimeout(30000); // 设置发送超时时间为30秒
producer.start();
Message msg = new Message("TopicTest", // Topic
"TagA", // Tag
("Hello RocketMQ").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
producer.send(msg);
producer.shutdown();
}
}
实战案例
实战项目的设计思路
本实战项目的目标是实现一个简单的订单系统,使用RocketMQ作为消息中间件,实现订单创建和支付通知的功能。订单创建和支付通知是两个异步操作,通过RocketMQ的消息中间件可以实现这两个操作的解耦,提高系统的扩展性和稳定性。
设计思路如下:
- 订单创建:用户提交订单后,订单服务会创建一个订单,并将订单信息发送到RocketMQ的订单创建Topic。
- 支付通知:支付服务会订阅订单创建Topic,接收到订单创建消息后,会向RocketMQ的支付通知Topic发送支付通知消息。
- 订单支付:支付服务会订阅支付通知Topic,接收到支付通知消息后,会向订单服务发送支付成功的消息。
- 订单完成:订单服务会订阅支付成功的Topic,接收到支付成功的消息后,会更新订单状态为支付完成。
// 订单创建服务
public class OrderService {
public void createOrder(String orderId) throws Exception {
// 创建订单
// 发送订单创建消息
Message msg = new Message("OrderCreateTopic", // Topic
"TagA", // Tag
("Order Id: " + orderId).getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
producer.send(msg);
}
}
// 支付服务
public class PaymentService {
public void onOrderCreated(String orderId) throws Exception {
// 发送支付通知消息
Message msg = new Message("PaymentNotifyTopic", // Topic
"TagA", // Tag
("Order Id: " + orderId).getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
producer.send(msg);
}
public void onPaymentSuccess(String orderId) throws Exception {
// 发送支付成功消息
Message msg = new Message("PaymentSuccessTopic", // Topic
"TagA", // Tag
("Order Id: " + orderId).getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
producer.send(msg);
}
}
// 订单服务
public class OrderService {
public void onPaymentSuccess(String orderId) throws Exception {
// 更新订单状态为支付完成
}
}
实战项目的部署与运行
部署与运行实战项目,需要先启动RocketMQ的Name Server和Broker,然后启动订单服务和支付服务。订单服务和支付服务都需要配置消息生产者和消费者,确保消息能够正常发送和接收。
// 启动RocketMQ的Name Server和Broker
nohup sh bin/mqnamesrv &
nohup sh bin/mqbroker -n 127.0.0.1:9876 &
// 订单服务
public class OrderService {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("OrderServiceProducer");
producer.setNamesrvAddr("localhost:9876");
producer.start();
Message msg = new Message("OrderCreateTopic", // Topic
"TagA", // Tag
("Order Id: 1").getBytes(RemotingHelper.DEFAULT_CHARSET), // body
1000); // timeout
producer.send(msg);
producer.shutdown();
}
}
// 支付服务
public class PaymentService {
public static void main(String[] args) throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("PaymentServiceConsumer");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("OrderCreateTopic", "*");
consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
for (MessageExt msg : msgs) {
String orderId = new String(msg.getBody());
// 处理订单创建消息
onOrderCreated(orderId);
}
return ConsumeOrderlyStatus.SUCCESS;
});
consumer.start();
}
}
部署并运行上述代码后,订单服务会发送订单创建消息到RocketMQ,支付服务会接收到订单创建消息后发送支付通知消息,订单服务会接收到支付成功的消息后更新订单状态。
共同学习,写下你的评论
评论加载中...
作者其他优质文章