RocketMQ(三)

RocketMQ如何保证不丢失数据

我们将消息流程分为如下三大部分,每一部分都有可能会丢失数据。

  • 生产阶段:Producer通过网络将消息发送给Broker,这个发送可能会发生丢失,比如网络延迟不可达等。
  • 存储阶段:Broker肯定是先把消息放到内存的,然后根据刷盘策略持久化到硬盘中,刚收到Producer的消息,再内存中了,但是异常宕机了,导致消息丢失。
  • 消费阶段:消费失败了其实也是消息丢失的一种变体吧。

Producer生产阶段

① 采取send()同步发消息。 有三种send方法,同步发送、异步发送、单向发送。我们可以采取同步发送的方式进行发送消息,发消息的时候会同步阻塞等待broker返回的结果,如果没成功,则不会收到SendResult,这种是最可靠的。其次是异步发送,再回调方法里可以得知是否发送成功。单向发送(OneWay)是最不靠谱的一种发送方式,我们无法保证消息真正可达。

②发送失败后可以重试,设置重试次数。默认3次。

Broker存储阶段

①修改刷盘策略为同步刷盘。默认情况下是异步刷盘的。

②集群部署,若想很严格的保证Broker存储消息阶段消息不丢失,Producer发消息到Broker后,Broker的Master节点先持久化到磁盘中,然后同步数据给Slave节点,Slave节点同步完且落盘完成后才会返回给Producer说消息ok了。

Consumer消费阶段

消费失败了其实也是消息丢失的一种变体。

①完全消费正常后在进行手动ack确认。消费者会先把消息拉取到本地,然后进行业务逻辑,业务逻辑完成后手动进行ack确认,这时候才会真正的代表消费完成。而不是说pull到本地后消息就算消费完了。

②消息消费失败自动重试。如果消费消息失败了,没有进行ack确认,则会自动重试,重试策略和次数(默认15次)

上面在解决消息顺序问题时,引入了一个新的问题,就是消息重复。造成消息的重复的根本原因是:网络不可达。RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重。只要通过网络交换数据,就无法避免这个问题。可以换一种理解:如果消费端收到两条一样的消息,应该怎样处理?

消息重复消费如何解决?

RocketMQ不解决消息重复的问题,需要我们自己在业务端实现。

分两种场景,第一是第一次发的消息已经消费成功,只是因为网络问题没有成功发出ack给broker,第二是消息消费失败。

1、消费端处理消息的业务逻辑保持幂等性,不管来多少条重复消息,最后处理的结果都一样
2、保证每条消息都有唯一编号,且保证消息处理成功后,将消息唯一id记录到日志中,或者记录到redis中。如果新到的消息ID已经在日志表或者redis中,那么就不再处理这条消息。

顺序消息

消息有序指的是一类消息消费时,能按照发送的顺序来消费。例如:一个订单产生了三条消息分别是订单创建、订单付款、订单完成。消费时要按照这个顺序消费才能有意义,但是同时订单之间是可以并行消费的。RocketMQ可以严格的保证消息有序。

顺序消息分为全局顺序消息与分区顺序消息,全局顺序是指某个Topic下的所有消息都要保证顺序;部分顺序消息只要保证每一组消息被顺序消费即可。

一般业务中只要保证部分业务的分区顺序消费就可以了,比如订单产生了三条消息分别是订单创建、订单付款、订单完成。可以把订单号相同的消息发到同一个队列里面,然后单线程取数据,就可以实现消息按照顺序进行消费。

消息积压解决方案  

  如果生产环境中consumer半夜挂掉了,项目数据量大的情况下第二天可能有一千万条消息积压在broker中。过多的数据积压不仅占用磁盘空间,还会影响MQ性能。那么这个时候应该怎么办呢。
  修复consumer,然后慢慢消费吗?比如rocketmq默认一个topic是4个queue,假如处理一条消息需要1秒,用4个consumer同时进行消费,也需要10000000÷4÷60=42分钟才能消费完。那新的消息怎么办呢?
解决方案:
  由于堆积的topic里面message queue数量固定,即使我们这时增加consumer的数量,它也不能分配到message queue。这时我们可以写一个分发程序做一个临时topic队列扩充,来提高消费者能力。程序从旧的topic中读取到新的topic,只是新的topic的queue可以指定多一点(理论上可以无限扩充,正常1000以内),然后启动更多的consumer在临时新的topic里面消费。

猜你喜欢

转载自blog.csdn.net/weixin_46217160/article/details/116055072