一、MQ数据交互
MQ怎么保证消息不丢失?首先先确认哪些场景会丢消息:一条消息从生产到消费主要经历下面几个主要阶段。
MQ数据交互二、生产阶段
2.1 定义
消息在Producer创建,经过网络传输发送到Broker端。
2.2 说明
在生产阶段,消息队列通过最常用的请求确认机制,来保证消息的可靠传递。当你的代码调用发送消息方法时,消息队列的客户端会把消息发送到 Broker,Broker 收到消息后,会给客户端返回一个确认响应,表明消息已经收到了。客户端收到响应后,完成了一次正常消息的发送。只要 Producer 收到了 Broker 的Ack响应,就可以保证消息在生产阶段不会丢失。有些消息队列在长时间没收到发送确认响应后,会自动重试,如果重试再失败,就会以返回值或者异常的方式告知用户。
2.3 kafka为例
这里以kafka为例举例说明一下:kafka生产者有个参数acks参数配置。
2.3.1 acks=0
acks = 0如果设置为零,那么生产者将完全不会管服务器是否收到消息,该记录将立即添加到套接字缓冲区中并视为已发送。返回值的偏移量将始终等于 -1,该方式具有最大的吞吐量。
2.3.2 acks=1
当leader接受到消息就会直接给客户端返回成功,一般情况下这种模式都能很好地保证数据的不丢失只有在laeder接受到数据,然后还没来得及同步到follower,就挂掉了才会导致数据的丢失,这种概率还是比较小的。这也是默认的选择方式,兼具较好的吞吐和较高的可靠性。
2.3.3 acks=-1或者acks=all
当leader接受到消息,并同步到了一定数量的follower,才向生产者发生成功的消息,同步到的follower数量由 broker 端的 min.insync.replicas 决定除非一些不可抗力因素,这种方式基本可以确保数据完全不丢失。
三、存储阶段
3.1 定义
在这个阶段,消息在Broker端存储,如果是集群,消息会在这个阶段被复制到其他的副本上。
3.2 说明
3.2.1 单节点
单个节点的Broker,需要配置Broker参数,在收到消息后,将消息写入磁盘后再给Producer 返回确认响应,这样即使发生宕机,由于消息已经被写入磁盘,就不会丢失消息,恢复后还可以继续消费。
3.2.2 多节点
Broker是由多个节点组成的集群,需要将Broker集群配置成:至少将消息发送到2个以上的节点,再给客户端回复发送确认响应。这样当某个Broker宕机时,其他的Broker 可以替代宕机的Broker,也不会发生消息丢失。
四、消费阶段
消费阶段采用和生产阶段类似的确认机制来保证消息的可靠传递,客户端从Broker拉取消息后,执行用户的消费业务逻辑,成功后,才会给Broker发送消费确认响应。如果Broker没有收到消费确认响应,下次拉消息的时候还会返回同一条消息,确保消息不会在网络传输过程中丢失,也不会因为客户端在执行消费逻辑中出错导致丢失。
五、消息丢失原因
生产者产生消息时,由于网络原因发送到 MQ 失败了、MQ 服务器持久化,存储磁盘时出现异常、Kafka和RocketMQ 的 offset 被回调时,略过了很多消息、消费者刚读取消息,已经 ACK 确认,但业务还没处理完,服务就被重启了。
六、处理方案
为了解决这个问题,我们可以增加一张消息发送表。
1、当生产者发完消息之后,会往该表中写入一条数据(msgId、status),状态 status 标记为待确认。
2、如果消费者读取消息之后,调用生产者的 API 更新该消息的status为已确认。
3、有个job(xxljob) 每隔一段时间检查一次消息发送表,如果5分钟(这个时间可以根据实际情况来定)后还有状态是待确认的消息,则认为该消息已经丢失了,重新发条消息。
转载自:MQ怎么保证消息不丢失?
网友评论