前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >对线面试官 - MQ数据丢失问题的解决方案

对线面试官 - MQ数据丢失问题的解决方案

作者头像
@派大星
发布2023-09-08 17:18:27
1860
发布2023-09-08 17:18:27
举报
文章被收录于专栏:码上遇见你码上遇见你

书接上文。这次继续聊一聊MQ,往期文章参考:

对线面试官-为什么要使用MQ

对线面试官 - MQ经典面试题之高可用性及幂等性

面试官:继上次你对MQ的回答,我还有一些疑问想要针对MQ。我们继续聊一聊?

派大星:好的,当然可以。

面试官:OK,那我们继续上次的话题,就是MQ如何保证消息的可靠性,或者说如何保证消息不丢失呢?

派大星:这种情况需要就不同情况进行分析。主要是有三张场景会导致消息丢失的问题。

  1. 生产者丢失了消息
  2. MQ丢失了消息
  3. 消费的时候丢失了消息

面试官:嗯,不错,那你能就每种情况简单聊一聊吗?

派大星:可以,首先我先简单说一下RabbitMQ丢失消息如何解决。每种消息丢失的情况的解决方案大致如下图所示:

  • 首先来说一说生产者丢失了消息:

主要场景是:写消息等过程中消息还没有到达MQ的时候,在网络传输的过程中就将消息丢失了;或者消息到了RabbitMQ但是MQ内部错乱没有存储消息导致消息丢失。

解决方案1:可以使用RabbitMQ事务机制,具体配置如下:

代码语言:javascript
复制
channel.txSelect();
try{
    // 发送消息
}catch{
    channel.txRollback();
}
channel.txCommit();

但是该种方案也有弊端:因为是事务机制,所以是同步阻塞的,这样就会导致生产者发送消息的吞吐量大大下降解决方案2:把channel设置成confirm模式,发送一个消息就不用管了,RabbitMQ如果接收到了这个消息就会回调生产者本地的一个接口,通知你说这条消息已经发送成功并且接收成功,反之也会通知。这种方式的吞吐量也会高一些。

  • 其次说一些RabbitMQ自己弄丢了消息

这种情况的解决方案可以将RabbitMQ设置为持久化。除非有及其罕见的情况RabbitMQ还没来得及持久化自己就挂了,可能会导致少量的数据丢失,当然这种概率是很小的。

  • 最后便是第三种情况:消费者丢失了消息

只有当你打开了消费者的autoAck的这样一个机制:你消费到了数据之后消费者会自动通知RabbitMQ说我已经消费到了这条数据;这样会出现一种情况:假设你消费到了一条数据但是还没有处理完,此时消费者就自动autoAck了。此时恰巧消费者系统服务挂了,消息还没来得及处理而且RabbitMQ以为该消息已经处理掉了。解决方案便是关掉RabbitMQ的自动ACK机制

面试官:不错,刚刚你有提到RabbitMQ设置持久化。你知道它怎么配置持久化吗:

派大星:直到的。具体步骤如下(注意两者缺一不可,需同时设置):

  • 创建queue的时候将其设置为持久化的,这样保证RabbitMQ持久化queue的元数据,但是不会持久化queue里的数据
  • 另外发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化。此时RabbitMQ就会将消息持久化到磁盘上去。

面试官:不错,但是我们这边实际工作中用的MQ是Kafka居多,关于Kafka消息丢失就以上情况你了解具体的解决方案吗?

派大星:这个也了解一些。

  • 首先说一下。Kafka中消费者弄丢了消息的场景:

具体过程为消费者自动提交了offset,其实消息还没有处理完。和RabbitMQ情况差不多。解决方案为:就是关闭自动提交offset,手动提交offset

  • 其次说一下Kafka弄丢了消息

主要表现形式为:Kafka的leader接收到了消息但是还没来得及同步给follwer就挂了,此时follwer变成了leader。导致数据丢失。解决方案为:需要设置4个参数:

  1. 给topic设置replication.replicas参数,这个值必须要大于1,也就是要求每个parttion只要有两个副本。
  2. 在Kafka服务端设置min.insync.replicas参数:这个值必须要大于1,这个是要求一个leader只要感知到最少有一个follwer还跟自己保持联系,这样才能确保leader还有一个follwer。
  3. 在producer段设置ack=all:这个要求是每条数据必须是写入所有的replica之后,才能认为是成功了。
  4. 在producer端设置retries=MAX:这个要求一旦写入失败,就无限重试,卡在这里。

按照上述配置后至少保证了在Kafka段在leader所在的broker发生故障进行leader切换时,数据不会丢失。

  • 最后聊一下生产者丢失数据的情况

如果是按照上述方式配置了ack=all则一定不会丢,要求是:你的leader接收到消息,所有的follwer都同步到了消息之后,才认为本次消息发送成功,否则生产者会重试无限次。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上遇见你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档