RocketMQ 是一款开源的分布式消息队列系统,由阿里巴巴集团开发并开源。它是为了满足大规模分布式系统中的消息通信和异步解耦需求而设计的,具有高吞吐量、低延迟、可靠性强等特点。下面将详细介绍 RocketMQ 的架构、组件和关键特性。
以下是RocketMQ界面:
主流的消息中间件的传输模型主要为点对点模型和发布订阅模型。
点对点模型也叫队列模型,具有如下特点:
发布订阅模型具有如下特点:
传输模型对比
点对点模型和发布订阅模型各有优势,点对点模型更为简单,而发布订阅模型的扩展性更高。 RocketMQ 使用的传输模型为发布订阅模型,因此也具有发布订阅模型的特点。
1)普通消息发送
Apache RocketMQ可用于以三种方式发送消息:同步、异步和单向传输。前两种消息类型是可靠的,因为无论它们是否成功发送都有响应。
2)延时消息发送
延迟消息发送是指消息发送到Apache RocketMQ后,并不期望立马投递这条消息,而是延迟一定时间后才投递到Consumer进行消费。
在分布式定时调度触发、任务超时处理等场景,需要实现精准、可靠的延时事件触发。使用 RocketMQ 的延时消息可以简化定时调度任务的开发逻辑,实现高性能、可扩展、高可靠的定时触发能力。
public class ScheduledMessageProducer {
public static void main(String[] args) throws Exception {
// Instantiate a producer to send scheduled messages
DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
// Launch producer
producer.start();
int totalMessagesToSend = 100;
for (int i = 0; i < totalMessagesToSend; i++) {
Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
// This message will be delivered to consumer 10 seconds later.
message.setDelayTimeLevel(3);
// Send the message
producer.send(message);
}
// Shutdown producer after use.
producer.shutdown();
}
}
3)顺序消息发送
顺序消息是一种对消息发送和消费顺序有严格要求的消息。
对于一个指定的Topic,消息严格按照先进先出(FIFO)的原则进行消息发布和消费,即先发布的消息先消费,后发布的消息后消费。在 RocketMQ 中支持分区顺序消息,如下图所示。我们可以按照某一个标准对消息进行分区(比如图中的ShardingKey),同一个ShardingKey的消息会被分配到同一个队列中,并按照顺序被消费。
需要注意的是 RocketMQ 消息的顺序性分为两部分,生产顺序性和消费顺序性。只有同时满足了生产顺序性和消费顺序性才能达到上述的FIFO效果。
4)事务消息发送
在一些对数据一致性有强需求的场景,可以用 RocketMQ 事务消息来解决,从而保证上下游数据的一致性。
事务消息交互流程如下图所示。
5)应答消息发送及接收
RocketMQ中,消息的应答主要分为两个方面:发送方的应答和消费方的应答。
通过应答机制,RocketMQ可以确保消息的可靠性传输和处理。发送方可以根据应答结果判断消息是否发送成功,消费方可以通过应答告知Broker消息的处理结果。这样可以保证消息系统的可靠性和一致性。
public class ManualAckConsumer {
public static void main(String[] args) throws MQClientException {
// 创建消费者实例
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group_name");
// 设置NameServer地址
consumer.setNamesrvAddr("localhost:9876");
// 订阅Topic和Tag
consumer.subscribe("TopicTest", "*");
// 注册消息监听器
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List messages, ConsumeConcurrentlyContext context) {
for (MessageExt message : messages) {
try {
// 处理消息
System.out.println("收到消息:" + new String(message.getBody()));
// 模拟业务处理成功
boolean success = true;
if (success) {
// 手动ACK确认消息消费成功
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
} else {
// 手动ACK确认消息消费失败
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
} catch (Exception e) {
e.printStackTrace();
// 异常情况下,手动ACK确认消息消费失败
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
}
// 消费失败
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
// 启动消费者
consumer.start();
System.out.println("消费者已启动");
}
}
RocketMQ 提供了三种消息发送方式,分别是同步发送、异步发送和单向发送。
public class SyncProducer {
public static void main(String[] args) throws MQClientException, InterruptedException {
// 创建生产者实例
DefaultMQProducer producer = new DefaultMQProducer("group_name");
// 设置NameServer地址
producer.setNamesrvAddr("localhost:9876");
// 启动生产者
producer.start();
try {
// 创建消息实例,指定Topic、Tag和消息内容
Message message = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
// 发送消息并等待返回结果
SendResult sendResult = producer.send(message);
// 判断消息发送状态
if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
System.out.println("消息发送成功");
} else {
System.out.println("消息发送失败");
}
} catch (Exception e) {
e.printStackTrace();
}
// 关闭生产者实例
producer.shutdown();
}
}
public class AsyncProducer {
public static void main(String[] args) throws MQClientException, InterruptedException {
// 创建生产者实例
DefaultMQProducer producer = new DefaultMQProducer("group_name");
// 设置NameServer地址
producer.setNamesrvAddr("localhost:9876");
// 启动生产者
producer.start();
try {
// 创建消息实例,指定Topic、Tag和消息内容
Message message = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
// 发送消息并注册回调
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("消息发送成功");
}
@Override
public void onException(Throwable e) {
System.out.println("消息发送失败:" + e.getMessage());
}
});
// 等待异步发送结果
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭生产者实例
producer.shutdown();
}
}
public class OnewayProducer {
public static void main(String[] args) throws MQClientException, InterruptedException {
// 创建生产者实例
DefaultMQProducer producer = new DefaultMQProducer("group_name");
// 设置NameServer地址
producer.setNamesrvAddr("localhost:9876");
// 启动生产者
producer.start();
try {
// 创建消息实例,指定Topic、Tag和消息内容
Message message = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
// 发送单向消息,无需等待发送结果
producer.sendOneway(message);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭生产者实例
producer.shutdown();
}
}
在 RocketMQ 的领域模型中,消费者分组的位置和流程如下:
RocketMQ提供两种分组模式,集群模式(Cluster Mode)和广播模式(Broadcast Mode)。
集群消费模式适用于每条消息只需要被处理一次的场景,也就是说整个消费组会Topic收到全量的消息,而消费组内的消费分担消费这些消息,因此可以通过扩缩消费者数量,来提升或降低消费能力,具体示例如下图所示,是最常见的消费方式。
// 设置消费模式为集群模式
consumer.setMessageModel(MessageModel.CLUSTERING);
广播消费模式适用于每条消息需要被消费组的每个消费者处理的场景,也就是说消费组内的每个消费者都会收到订阅Topic的全量消息,因此即使扩缩消费者数量也无法提升或降低消费能力,具体示例如下图所示。
// 设置消费模式为广播模式
consumer.setMessageModel(MessageModel.BROADCASTING);
MQ的消费模式可以大致分为两种,一种是推Push,一种是拉Pull。
Push是服务端主动推送消息给客户端,优点是及时性较好,但如果客户端没有做好流控,一旦服务端推送大量消息到客户端时,就会导致客户端消息堆积甚至崩溃。
Pull是客户端需要主动到服务端取数据,优点是客户端可以依据自己的消费能力进行消费,但拉取的频率也需要用户自己控制,拉取频繁容易造成服务端和客户端的压力,拉取间隔长又容易造成消费不及时。
RocketMQ在topic过滤基础上可以增加tag进一步筛选
Message message = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes());
消息的持久化存储:RocketMQ 将消息存储到磁盘,以确保消息的可靠性。
RocketMQ是一种分布式消息中间件,它支持消息的持久化,以确保消息在系统异常或故障发生时不会丢失。RocketMQ提供了多种持久化方式,包括同步刷盘和异步刷盘,以满足不同场景下的性能和可靠性需求。
RocketMQ的持久化机制如下:
集群模式下,同一个消费组内的消费者会分担收到的全量消息,这里的分配策略是怎样的?如果扩容消费者是否一定能提升消费能力?
RocketMQ 提供了多种集群模式下的分配策略,包括平均分配策略、机房优先分配策略、一致性hash分配策略等,可以通过如下代码进行设置相应负载均衡策略
consumer.setAllocateMessageQueueStrategy(new AllocateMessageQueueAveragely());
默认的分配策略是平均分配,这也是最常见的策略。平均分配策略下消费组内的消费者会按照类似分页的策略均摊消费。
部署方式 | RocketMQrocketmq.apache.org/zh/docs/4.x/deployment/01deploy
=================================
如果文章对你有帮助,请不要忘记加个关注、点个赞!必回关!!!