RocketMQ高级特性一

目录

前言

普通消息(Regular Messages)

普通消息生命周期

使用限制

使用场景

原理机制

优缺点

代码示例

定时或延迟消息(Delayed Messages)

定时消息生命周期

使用限制​

使用场景

原理机制

优缺点

代码示例

顺序消息(Message Ordering)

 顺序消息生命周期

使用限制​

使用场景

原理机制

优缺点

代码示例

事务消息(Transactional Messages)

事务消息生命周期

​编辑

使用限制​

使用场景

原理机制

优缺点

代码示例

总结


前言

本文主要详细讲解 RocketMQ 的四种消息类型:普通消息、定时或延迟消息、顺序消息、事务消息。每种消息类型包括使用场景、原理机制、优缺点和代码示例。注:部分图片集信息来源于Apache

普通消息(Regular Messages)

普通消息是Apache RocketMQ基本消息功能,支持生产者和消费者的异步解耦通信。

普通消息生命周期
  • 初始化:消息被生产者构建并完成初始化,待发送到服务端的状态。

  • 待消费:消息被发送到服务端,对消费者可见,等待消费者消费的状态。

  • 消费中:消息被消费者获取,并按照消费者本地的业务逻辑进行处理的过程。 此时服务端会等待消费者完成消费并提交消费结果,如果一定时间后没有收到消费者的响应,Apache RocketMQ会对消息进行重试处理。具体信息,请参见消费重试

  • 消费提交:消费者完成消费处理,并向服务端提交消费结果,服务端标记当前消息已经被处理(包括消费成功和失败)。 Apache RocketMQ默认支持保留所有消息,此时消息数据并不会立即被删除,只是逻辑标记已消费。消息在保存时间到期或存储空间不足被删除前,消费者仍然可以回溯消息重新消费。

  • 消息删除:Apache RocketMQ按照消息保存机制滚动清理最早的消息数据,将消息从物理文件中删除。更多信息,请参见消息存储和清理机制

使用限制

普通消息仅支持使用MessageType为Normal主题,即普通消息只能发送至类型为普通消息的主题中,发送的消息的类型必须和主题的类型一致。

使用场景
  • 数据集成传输:适用于大多数消息传递需求,如日志收集、通知推送等。

  • 微服务异步解耦:如异步任务执行、数据处理、订单下单等。

原理机制

普通消息是 RocketMQ 中最基本的消息类型。生产者将消息发送到指定的主题(Topic),Broker 存储消息,消费者从 Broker 拉取消息进行处理。消息的存储和传递机制如下:

  1. 消息生产:生产者将消息发送到指定的 Topic 和 Queue 中。每个 Topic 可以有多个 Queue,用于实现并发处理。
  2. 消息存储:消息存储在 Broker 的文件系统中。消息按照时间顺序存储在日志文件中,文件系统的高效写入和索引机制确保了消息的持久化。
  3. 消息消费:消费者从 Topic 的 Queue 中拉取消息进行处理。消费者可以是并发处理的,也可以是顺序处理的。
优缺点
  • 优点
    • 简单易用:适合一般的消息传递需求,无需复杂配置。
    • 高吞吐量:支持大规模的消息生产和消费,性能优越。
  • 缺点
    • 消息顺序性:在高并发场景中,可能无法保证消息的顺序。
    • 事务支持:不支持复杂的事务管理,无法保证跨系统的一致性。
代码示例

生产者发送普通消息:

DefaultMQProducer producer = new DefaultMQProducer("regular_producer_group");
producer.setNamesrvAddr("localhost:9876");
producer.start();

Message msg = new Message("TopicTest", "TagA", "KEY", "Hello RocketMQ".getBytes());
SendResult sendResult = producer.send(msg);
System.out.printf("Send Result: %s%n", sendResult);

producer.shutdown();

消费者接收普通消息:

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("regular_consumer_group");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TopicTest", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.printf("Received Message: %s%n", new String(msg.getBody()));
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
});
consumer.start();

定时或延迟消息(Delayed Messages)

定时消息是 Apache RocketMQ 提供的一种高级消息类型,消息被发送至服务端后,在指定时间后才能被消费者消费。通过设置一定的定时时间可以实现分布式场景的延时调度触发效果。

定时时间设置原则

  • Apache RocketMQ 定时消息设置的定时时间是一个预期触发的系统时间戳,延时时间也需要转换成当前系统时间后的某一个时间戳,而不是一段延时时长。

  • 定时时间的格式为毫秒级的Unix时间戳,您需要将要设置的时刻转换成时间戳形式。具体方式,请参见Unix时间戳转换工具

  • 定时时间必须设置在定时时长范围内,超过范围则定时不生效,服务端会立即投递消息。

  • 定时时长最大值默认为24小时,不支持自定义修改,更多信息,请参见参数限制

  • 定时时间必须设置为当前时间之后,若设置到当前时间之前,则定时不生效,服务端会立即投递消息。

示例如下:

  • 定时消息:例如,当前系统时间为2022-06-09 17:30:00,您希望消息在下午19:20:00定时投递,则定时时间为2022-06-09 19:20:00,转换成时间戳格式为1654773600000。

  • 延时消息:例如,当前系统时间为2022-06-09 17:30:00,您希望延时1个小时后投递消息,则您需要根据当前时间和延时时长换算成定时时刻,即消息投递时间为2022-06-09 18:30:00,转换为时间戳格式为1654770600000。

定时消息生命周期

  • 初始化:消息被生产者构建并完成初始化,待发送到服务端的状态。

  • 定时中:消息被发送到服务端,和普通消息不同的是,服务端不会直接构建消息索引,而是会将定时消息单独存储在定时存储系统中,等待定时时刻到达。

  • 待消费:定时时刻到达后,服务端将消息重新写入普通存储引擎,对下游消费者可见,等待消费者消费的状态。

  • 消费中:消息被消费者获取,并按照消费者本地的业务逻辑进行处理的过程。 此时服务端会等待消费者完成消费并提交消费结果,如果一定时间后没有收到消费者的响应,Apache RocketMQ会对消息进行重试处理。具体信息,请参见消费重试

  • 消费提交:消费者完成消费处理,并向服务端提交消费结果,服务端标记当前消息已经被处理(包括消费成功和失败)。 Apache RocketMQ 默认支持保留所有消息,此时消息数据并不会立即被删除,只是逻辑标记已消费。消息在保存时间到期或存储空间不足被删除前,消费者仍然可以回溯消息重新消费。

  • 消息删除:Apache RocketMQ按照消息保存机制滚动清理最早的消息数据,将消息从物理文件中删除。更多信息,请参见消息存储和清理机制

使用限制

消息类型一致性

定时消息仅支持在 MessageType为Delay 的主题内使用,即定时消息只能发送至类型为定时消息的主题中,发送的消息的类型必须和主题的类型一致。

定时精度约束

Apache RocketMQ 定时消息的定时时长参数精确到毫秒级,但是默认精度为1000ms,即定时消息为秒级精度。

Apache RocketMQ 定时消息的状态支持持久化存储,系统由于故障重启后,仍支持按照原来设置的定时时间触发消息投递。若存储系统异常重启,可能会导致定时消息投递出现一定延迟。

使用场景
  • 分布式定时调度:电商系统中的订单如果在一定时间内未支付,需要自动取消。

  • 定时提醒:设置定时提醒功能,按照预定时间发送提醒消息。

原理机制

RocketMQ 的延迟消息机制基于延迟级别(Delay Levels),每个级别对应固定的延迟时间。其原理如下:

  1. 延迟级别配置:RocketMQ 在 Broker 中预定义了多个延迟级别(从 1 秒到 24 小时),每个级别对应一个固定的延迟时间。
  2. 消息发送:生产者发送消息时设置延迟级别(如设置为 3 代表 10 秒延迟)。消息首先存储在延迟队列中。
  3. 延迟队列:消息在延迟队列中等待到达指定的延迟时间。一旦延迟时间到达,消息会被转移到实际的消费队列中进行消费。
优缺点
  • 优点
    • 简洁实现:通过设置延迟级别实现延迟功能,无需额外的编程。
    • 性能高效:基于队列的延迟处理,性能开销小。
  • 缺点
    • 延迟级别固定:只能使用预定义的延迟级别,灵活性有限。
    • 精度问题:延迟时间的精度受到延迟级别的限制,可能会有一定误差。
代码示例

发送延迟消息:

DefaultMQProducer producer = new DefaultMQProducer("delay_producer_group");
producer.setNamesrvAddr("localhost:9876");
producer.start();

Message msg = new Message("TopicTest", "TagA", "KEY", "Hello RocketMQ".getBytes());
msg.setDelayTimeLevel(3);  // 设置延迟级别,3 代表10秒延迟
SendResult sendResult = producer.send(msg);
System.out.printf("Send Result: %s%n", sendResult);

producer.shutdown();

顺序消息(Message Ordering)

顺序消息是 Apache RocketMQ 提供的一种高级消息类型,支持消费者按照发送消息的先后顺序获取消息,从而实现业务场景中的顺序处理。 相比其他类型消息,顺序消息在发送、存储和投递的处理过程中,更多强调多条消息间的先后顺序关系。

Apache RocketMQ 顺序消息的顺序关系通过消息组(MessageGroup)判定和识别,发送顺序消息时需要为每条消息设置归属的消息组,相同消息组的多条消息之间遵循先进先出的顺序关系,不同消息组、无消息组的消息之间不涉及顺序性。

基于消息组的顺序判定逻辑,支持按照业务逻辑做细粒度拆分,可以在满足业务局部顺序的前提下提高系统的并行度和吞吐能力。

 顺序消息生命周期

  • 初始化:消息被生产者构建并完成初始化,待发送到服务端的状态。

  • 待消费:消息被发送到服务端,对消费者可见,等待消费者消费的状态。

  • 消费中:消息被消费者获取,并按照消费者本地的业务逻辑进行处理的过程。 此时服务端会等待消费者完成消费并提交消费结果,如果一定时间后没有收到消费者的响应,Apache RocketMQ会对消息进行重试处理。具体信息,请参见消费重试

  • 消费提交:消费者完成消费处理,并向服务端提交消费结果,服务端标记当前消息已经被处理(包括消费成功和失败)。 Apache RocketMQ 默认支持保留所有消息,此时消息数据并不会立即被删除,只是逻辑标记已消费。消息在保存时间到期或存储空间不足被删除前,消费者仍然可以回溯消息重新消费。

  • 消息删除:Apache RocketMQ按照消息保存机制滚动清理最早的消息数据,将消息从物理文件中删除。更多信息,请参见消息存储和清理机制

备注

  • 消息消费失败或消费超时,会触发服务端重试逻辑,重试消息属于新的消息,原消息的生命周期已结束。

  • 顺序消息消费失败进行消费重试时,为保障消息的顺序性,后续消息不可被消费,必须等待前面的消息消费完成后才能被处理。

使用限制

顺序消息仅支持使用MessageType为FIFO的主题,即顺序消息只能发送至类型为顺序消息的主题中,发送的消息的类型必须和主题的类型一致。

使用场景
  • 订单处理:需要确保订单的创建、支付、发货等操作按顺序处理。
  • 金融交易:确保转账和扣款等操作按时间顺序进行。

原理机制

RocketMQ 通过两种主要机制支持顺序消息:

  1. 全局顺序

    • 机制:所有消息发送到同一个队列,消费者从这个队列中顺序拉取消息。适用于顺序要求非常严格的场景。
    • 实现:生产者将消息发送到一个单独的队列中,消费者顺序拉取,确保顺序性。
  2. 分区顺序

    • 机制:通过分区键(如订单 ID)将消息路由到特定的队列。每个队列内的消息按顺序消费,但不同队列之间的顺序不保证。
    • 实现:生产者基于某个分区键将消息发送到特定队列,消费者从这些队列中按顺序消费。
优缺点
  • 优点
    • 顺序保证:适用于需要严格顺序处理的场景。
    • 扩展性:分区顺序机制在保证顺序的同时支持高吞吐量。
  • 缺点
    • 全局顺序性能瓶颈:全局顺序适用于小规模应用,高负载下可能成为性能瓶颈。
    • 分区顺序局限:只能保证同一队列的顺序,跨队列的顺序无法保证。
代码示例

生产者发送顺序消息:

DefaultMQProducer producer = new DefaultMQProducer("order_producer_group");
producer.setNamesrvAddr("localhost:9876");
producer.start();

String[] tags = new String[]{"TagA", "TagB", "TagC"};
for (int i = 0; i < 10; i++) {
    Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i, ("Order " + i).getBytes());
    SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
        @Override
        public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
            int queueNumber = arg.hashCode() % mqs.size();
            return mqs.get(queueNumber);
        }
    }, i);  // i 作为分区键
    System.out.printf("Send Result: %s%n", sendResult);
}
producer.shutdown();

消费者消费顺序消息:

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order_consumer_group");
consumer.setNamesrvAddr("localhost:9876");
consumer.subscribe("TopicTest", "*");
consumer.registerMessageListener(new MessageListenerOrderly() {
    @Override
    public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
        for (MessageExt msg : msgs) {
            System.out.printf("Received Message: %s%n", new String(msg.getBody()));
        }
        return ConsumeOrderlyStatus.SUCCESS;
    }
});
consumer.start();

事务消息(Transactional Messages)

事务消息是 Apache RocketMQ 提供的一种高级消息类型,支持在分布式场景下保障消息生产和本地事务的最终一致性。

事务消息生命周期
  • 初始化:半事务消息被生产者构建并完成初始化,待发送到服务端的状态。

  • 事务待提交:半事务消息被发送到服务端,和普通消息不同,并不会直接被服务端持久化,而是会被单独存储到事务存储系统中,等待第二阶段本地事务返回执行结果后再提交。此时消息对下游消费者不可见。

  • 消息回滚:第二阶段如果事务执行结果明确为回滚,服务端会将半事务消息回滚,该事务消息流程终止。

  • 提交待消费:第二阶段如果事务执行结果明确为提交,服务端会将半事务消息重新存储到普通存储系统中,此时消息对下游消费者可见,等待被消费者获取并消费。

  • 消费中:消息被消费者获取,并按照消费者本地的业务逻辑进行处理的过程。 此时服务端会等待消费者完成消费并提交消费结果,如果一定时间后没有收到消费者的响应,Apache RocketMQ会对消息进行重试处理。具体信息,请参见消费重试

  • 消费提交:消费者完成消费处理,并向服务端提交消费结果,服务端标记当前消息已经被处理(包括消费成功和失败)。 Apache RocketMQ默认支持保留所有消息,此时消息数据并不会立即被删除,只是逻辑标记已消费。消息在保存时间到期或存储空间不足被删除前,消费者仍然可以回溯消息重新消费。

  • 消息删除:Apache RocketMQ按照消息保存机制滚动清理最早的消息数据,将消息从物理文件中删除。更多信息,请参见消息存储和清理机制

使用限制

消息类型一致性

事务消息仅支持在 MessageType 为 Transaction 的主题内使用,即事务消息只能发送至类型为事务消息的主题中,发送的消息的类型必须和主题的类型一致。

消费事务性

Apache RocketMQ 事务消息保证本地主分支事务和下游消息发送事务的一致性,但不保证消息消费结果和上游事务的一致性。因此需要下游业务分支自行保证消息正确处理,建议消费端做好消费重试,如果有短暂失败可以利用重试机制保证最终处理成功。

中间状态可见性

Apache RocketMQ 事务消息为最终一致性,即在消息提交到下游消费端处理完成之前,下游分支和上游事务之间的状态会不一致。因此,事务消息仅适合接受异步执行的事务场景。

事务超时机制

Apache RocketMQ 事务消息的生命周期存在超时机制,即半事务消息被生产者发送服务端后,如果在指定时间内服务端无法确认提交或者回滚状态,则消息默认会被回滚。事务超时时间,请参见参数限制


使用场景
  • 跨系统事务:确保分布式系统中的事务一致性,如银行转账。

  • 订单创建与库存管理:确保订单创建和库存扣减的一致性。

原理机制

RocketMQ 的事务消息机制包括:

  1. 预提交消息

    • 机制:生产者将消息发送到 Broker,但消息对消费者不可见。这是事务的第一阶段。
    • 实现:消息存储在特殊的预提交状态,直到本地事务结果被确认。
  2. 本地事务执行

    • 机制:生产者在本地系统中执行事务操作(如数据库操作),并根据结果决定是否提交或回滚消息。
  3. 事务提交或回滚

    • 机制:生产者通知 Broker 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。
    • 实现:生产者通过调用接口确认事务状态。
  4. 事务状态回查

    • 机制:Broker 在超时后回查生产者的事务状态以决定消息是否提交或回滚。这是为了处理网络异常等问题。
优缺点
  • 优点
    • 事务支持:支持分布式事务,保证消息传递的一致性。
    • 高效性:通过两阶段提交机制提高了事务处理效率。
  • 缺点
    • 实现复杂:需要处理本地事务和回查机制,增加了系统复杂度。
    • 回查延迟:回查机制可能导致事务状态确认的延迟,影响实时性。
代码示例

构建事务消息:

TransactionMQProducer producer = new TransactionMQProducer("trans_producer_group");
producer.setNamesrvAddr("localhost:9876");
producer.setTransactionListener(new TransactionListener() {
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        try {
            // 执行本地事务逻辑
            // 如果本地事务成功
            return LocalTransactionState.COMMIT_MESSAGE;
        } catch (Exception e) {
            // 如果本地事务失败
            return LocalTransactionState.ROLLBACK_MESSAGE;
        }
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        // 回查事务状态
        return LocalTransactionState.COMMIT_MESSAGE;
    }
});
producer.start();

Message msg = new Message("TopicTest", "TagA", "KEY", "Hello RocketMQ".getBytes());
producer.sendMessageInTransaction(msg, null);

总结

通过这些实践,可以深入理解 RocketMQ 的高级特性,并在实际项目中应用这些功能来处理复杂的消息传递需求。

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值