【中间件系列】RocketMQ消息的可靠性

​ 目前市面上比较流行的消息中间件有RocketMq、RabbitMQ、kafka。kafka着重是日志收集方面消息的可靠性不如两外两个,RocketMq、RabbitMQ的消息是比较可靠的,RocketMq由java编写,和java有一个天然的集成。RocketMq又是如何保证消息不丢失呢?

​ RocketMq消息可分为三个阶段,发送、保存、消费。

一、发送阶段

1.RocketMq发送类型

​ RocketMq发送类型有三种,同步发送,异步发送,单向发送。

​ 同步发送比较容易理解,就是发送完成之后返回发送状态。

​ 异步发送即在发送之后立即返回,发送的结果会通过回调函数进行返回。

​ 单向发送,类似一种UDP协议的广播,即发送之后,不管有没有发送成功,追求的是效率,在敏感的数据传输时不推荐使用。个人觉得发送场景不多,因为一般用RocketMq主要是看中消息的可靠性,效率好,不可靠的消息消息类型可以通过kafka代替。

2.内部重试机制

broke在集群模式的时候,通过send方法发送失败,会有一个内部的重试机制。发送逻辑如下:

  1. 至多重试3次。
  2. 如果发送失败,则轮询到下一个broke。
  3. 这个方法总耗时时间不超过sendMsgTimeout设置的时间,默认10秒。所有如果是超时异常,则不会在重试了。

3.RocketMq消息类型

​ RocketMq消息类型有 普通消息、顺序消息、延迟消息、事务消息

​ 普通消息比较简单也最常用,不再多说;

​ 顺序消息要保证顺序,需要所有的消息发送在一个队列上,保证了顺序,影响了效率。

​ 延迟消息常用于订单超时处理等等

​ 如上需要保证本地事务和发送消息的一致性。RocketMq提供了事务消息,即可以做到本地事务提交,消息发送。本地事务回滚,消息回滚。详细到 RocketMq事务消息

4.RocketMq发送返回值处理

​ 消息通过send方法发送的时候,只要不抛异常,就代表发送成功,但是有一些返回状态需要注意下。

  1. SEND_OK 消息发送成功
  2. FLUSH_DISK_TIMEOUT 消息发送成功,但是服务器刷盘超时,消息已经进入服务器队列,此时只有服务器宕机,消息才会丢失。
  3. FLUSH_SLAVE_TIMEOUT 消息发送成功,但是同步到Slave超时,消息已经进入服务器队列,此时只有服务器宕机,消息才会丢失。
  4. SLAVE_NOT_AVAILABLE 消息发送成功,但是Slave,消息已经进入服务器队列,此时只有服务器宕机,消息才会丢失。

对于发送失败的信息可保存到数据库中,通过定时器进行重发操作。

二、消息保存阶段

刷盘策略

消息到达RocketMq之后,RocketMq有持久化操作。RocketMq刷盘机制,可分为同步刷盘异步刷盘

  • 同步刷盘: 消息到达RocketMq之后,需要持久化完成才能返回

  • 异步刷盘:写完 page cache直接返回

    所以如要需要消息更加可靠,可设置同步刷盘。

三、消费阶段

消费者从RocketMq 拉取消息之后,需要ack成功才算是正常的消费完成。

   public static void main(String[] args) throws InterruptedException,
    MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
        consumer.setNamesrvAddr("192.168.31.40:9876");
        consumer.subscribe("TopicTest", "*");
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        consumer.start();
    }

如上,只有返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS才算消费完成。否则会进行重试。

messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

会按照如上时间进行再次消费,如果最后还是未能消费成功,则不再重试。此时,消息队列不会立刻将消息丢弃。死信队列的名称是在原队列名称前加%DLQ%。如果你还是不死心的话,觉得这条消息还能抢救一下,可以开启一个后台线程不断扫描死信队列然后继续重试,也可以通过使用console控制台对死信队列中的消息进行重发来使得消费者实例再次进行消费

回溯消费
回溯消费是指Consumer已经消费成功的消息,由于业务上需求需要重新消费,要支持此功能,Broker在向Consumer投递成功消息后,消息仍然需要保留。并且重新消费一般是按照时间维度,例如由于Consumer系统故障,恢复后需要重新消费1小时前的数据,那么Broker要提供一种机制,可以按照时间维度来回退消费进度。RocketMq支持按照时间回溯消费,时间维度精确到毫秒。

猜你喜欢

转载自blog.csdn.net/qq_30285985/article/details/107020356