当前位置: 首页 > 科技观察

2022双十一备战:一个小疏忽差点酿成大祸

时间:2023-03-13 01:05:33 科技观察

1。背景在过去一周左右的时间里,一直有项目组反馈遇到消息重复推送的问题,短时间内一条消息被多个消费者消费的问题消费者消费问题:同时给出证据,打印两条msgId相同的消息,两条间隔7s。说实话,因为最近负责了很多事情,而RocketMQ并不能保证消息会被重复消费,所以一开始没有引起足够的重视,只是简单说明一下RocketMQ的设计原理不保证重复消费,要求消费者实现幂等性。但是就是这个疏忽后来爆发了,整个集群的大部分消费群消费都出现了严重的抖动,导致消费群频繁积压,开始了一波紧锣密鼓的排查和在线止血操作,同时触发我的发现之旅。关于整个MQ集群消费组为什么会出现消费抖动,这里先悬念一下。本文想和大家聊一聊RocketMQ的哪些设计会导致消息消费的重复消费。2、探索RocketMQ的重复消费在RocketMQ的设计理念中,消息发送和消息消费的相关机制会带来消息的重复消费。接下来,我们将分别讨论它们。2.1发送消息时重试导致消息重复发送在RocketMQ中,由于消息的发送方无法实时感知Broker路由的变化,为了保证消息发送的高可用,RocketMQ在发送时引入了重试机制消息,客户端发送消息的过程比较简单如下图:即如果在发送消息的过程中,如果broker的传输抖动导致消息发送超时,发送超时不会意味着消息没有成功写入Broker,或者可能需要很长时间才能写入Broker,但是client等不及,判断失败,然后尝试找另外一个Broker发送消息,这样会导致发送两条消息,并且两条消息的msgId和消息体相同,但是在消息簇中有两条消息,即两条消息的msgId相同,但是offsetMsgId不同。这里我给大家科普一下RocketMQ中两个消息id的含义:msgId消息id,由发送者创建,全局唯一offsetMsgId消息偏移量,由Broker创建,记录了服务器的地址和消息的物理偏移量。如果消息发送者发送了两条消息,就会出现文章开头的情况,日志中会出现两条一模一样的日志。那么,如何判断消息重复消费是否是消息发送方的问题呢?其实很简单。我们只需要在打印的消息体的日志中添加以下三个属性,就可以轻松识别。这些属性如下:brokerName存储消息的broker名称queueId消息消费队列IDqueueOffset消息消费队列的偏移量如果打印的消息中这些参数相同,则可以断定消息是发送消息时重复发送。2.2消息消费时的重复消费介绍了发送消息时重复消费的可能性后,我们来探讨下消息消费者是否会引起重复消费。纵观我对RocketMQ的理解,RocketMQ消息消费中消息消费重复的原因主要有3个:最小点提交机制、消费点批量提交、消费组重平衡。新出的书《RocketMQ实战》目前50折。2.2.1最小点提交机制RocketMQ在消费消息时采用最小点提交机制,如下图所示:例如消息消费线程池中的3个消费者线程t1、t2、t3分别在处理消息偏移量1。,2,3消息,由于并发消费,如果t3线程先消费msg3,此时将站点提交给服务器,那么msg3的offset是否上报为最新的消费进度?显然不是,因为一旦3被设置为最新位置,但是此时offset1和2的消息还没有被消费成功,一旦消费者重启,下一次就会从offset3的消息开始消费,所以两条消息msg1和msg2将丢失。因此,为了保证消息消费者不丢失消息,RocketMQ采用了最小点提交机制,即线程t3虽然完成了消息3的消费,但它需要做的是先将msg3从处理队列中移除,然后选择处理队列中的最小偏移量作为位置上报,即t3线程消费完msg3后,会将msg1的偏移量提交给服务器。这也会带来另一个问题,消息的重复消费。比如t3消费msg3后,提交的位置就是msg1的位置。如果consumer重启,会继续从msg1开始消费,msg3会再次消费。.重复消费消息和丢失消息是两害相权取其轻。确保消息不丢失是重中之重。估计在设计上难免会出现重复消费消息的情况。2.2.2消费消息的批量提交机制消费一条消息后,需要将站点上报给服务器,但是如果每次消费消息都向服务器发送站点提交请求,服务器的性能肯定不会因此,为了保证服务器的稳定性,RocketMQ采用了批量提交站点的机制,如下图:客户端会先在本地缓存站点信息,然后发起一次站点提交到服务器每5秒。服务端收到clientsite提交机制后,只更新内存中的数据,然后每隔5s将内存中的数据持久化到磁盘。由于位置信息同步的延迟,如果客户端重启,会丢失部分位置信息,也会出现重复消费的情况。2.2.3重平衡导致重复消费。RocketMQ消费者在消费前首先需要对队列进行负载均衡。RocketMQ队列负载的一个基本原则:一个队列只会同时分配给一个消费者,一个消费者可以消费多个队列。当消费者数量或队列数量发生变化时,就会触发再平衡。示意图如下:首先,q3队列被c2负载消费,但是当有新的消费者加入时,q3队列被分配给c3,即c2消费者处理完q3的部分消息后,队列被丢弃,站点提交失败,所以在c3消费者上又消费了一些消息,同样造成重复消费。3、总结说明RocketMQ导致消息重复消费的几种情况。各位读者可以考虑一下。集群大面积重复消息,消息消费抖动,你认为是什么原因造成的??