【打怪升级】【rocketMq】如何保证消息零丢失

上面一篇文章中介绍了RocketMq的基本架构以及组件的能力。那么在RocketMq中,如何做到消息零丢失呢?

  • RocketMq哪些地方会丢失消息?

     扒拉出上一节的MQ消息消费的流程模型如下:

    

    分布式消息,数据丢失的最常见的地方是网络!由此得知:

    1.生产者发送至mq时存在消息丢失。

    2.消费者消费mq消息时存在消息丢失。

    3.mq收到消息后,持久化刷盘时会存在消息丢失。

    4.master收到消息,无法同步给slave并挂起时会存在消息丢失。

 

  • RocketMq之事务消息

    说到事务消息,先考虑一下我们之前提出的问题。如何保证消息不会丢失?

    其实对于MQ来说,最常见的方式:同步发送+重试机制,保证最少消费一次。(这种方式比较常见,这里先不做太多说明)

    Rocket还支持一种消息,叫TransactionMessage,事务消息。先上一张图:

    

    步骤1:producer产生消息后,发送给rocket,先进行一个half消息确认,将消息转发到HALF队列。

    步骤2:mq收到确认后,回调producer确认。

    步骤3:producer会执行TranscationListener中重写的executeLocalTranscation处理方法,先处理本地事务。

    步骤4:处理本地事务后,返回本地事务处理的结果:LocalTranscationStatus中有三个枚举,分别是:COMMIT_MESSAGE 提交消息;ROLLBACK MESSAGE 回滚消息;UNKNOW 未知结果:

      前两个比较简单,commit后消息会发送至broker messageQueue 消费者会感知到消息并消费;rollback认为事务异常回滚,消息会从临时队列中剔除,这一步消费者是没有感知的!

      unknow 如果我给mq返回一个未知的结果,它有以下几种情况:异步处理没有执行完,网络异常中断,服务挂起,或等待!

    步骤5:如果事务状态提交或回滚,它们的结果是被消费者感知消费或直接剔除。那如果在上一步中我们返回的是一个未知的结果,mq会回调我们的TranscationListener中重写的checkLocationTranscation,进一步检查我们的处理是否完成,如果在这里我们依旧返回了未知的结果,它就会重试的通过check获取处理的结果,当然这不是无限的重试,重试的机制与rocket默认重试机制类似,以延时等级去重试,当达到最大等级后消息将被丢弃。

    

    half消息首先是对消费者不可见的,因为消费者并没有订阅HALF的topic,本地事务处理正常,消息会通过half进行预发送,成功后mq挂掉,这时我们的本地事务不会执行,待mq恢复后重新检查发现检查失败直接对消息进行回滚,消息不会被消费者感知;如果本地事务处理异常,OP标记直接删除,消费者不会收到错误的消息;它保证了本地事务和生产消息的事务特性,提交或异常回滚。

    完整的流程,应该是这样:

    

 

  • MQ如何保证消息不丢失

    MQ在写入消息后,默认会将消息存储在一个cache中,它是pageCache-页缓存机制,这时如果实例挂掉还没来及的写入本地存储,就会发生消息丢失的情况。

    针对这种情况,我们可以设置mq的持久化刷盘机制为同步刷盘,写一个消息后就会立即同步将消息刷到本地持久化中,相当于绕过了pageCache缓存。flushDesk:提供了两种刷盘方式:ASYNC_FLUSH和SYNC_FLUSH。

    MQ集群在写入broker master后,如果来不及向slave同步消息,就挂掉也会出现消息丢失。

    针对这种情况,我们可以设置主从节点同步方式为同步信息,在写入消息后立即同步到slave。brokerRule:提供了三种同步方式:ASYNC_MASTER,SYNC_MASTER和SLAVE。

    如果是消费者在消费时由于网络丢失了数据,它有一个重试的机制,每次消费者消费到消息后,也需要给mq返回一个状态,来进行确认;如果没有确认消费完,表示消费失败了,它会把消息存起来放在延时队列里根据延时策略进行重试。那如果多次重试都无法正常消费,mq还提供了死信队列的机制保证这个消息不会被丢失。

    如果要完全做到零丢失,还有一点需要考虑,如果整个mq集群全部挂掉,短时间内所有的消息都是不可用的,这时可以将消息写入缓存或持久化做服务降级,通过单独的线程任务去监听mq,服务恢复后再把缓存中的消息写入mq中。

posted @ 2023-03-08 15:44  青柠_fisher  阅读(248)  评论(0编辑  收藏  举报