如何保证MQ消息队列的可靠性传输

MQ的基本原则:数据不能多一条,也不能少一条,不能多,就是要保证幂等性,不能少,就是要保证可靠性,数据不能发生丢失

RabbitMQ

生产者丢失数据

可能在生产者向RabbitMQ发送消息的中途发生数据丢失

第一种方法是使用RabbitMQ提供的事务机制,在生产者发送数据之前开启RabbitMQ 事务channel.txSelect,然后发送消息,如果该消息没有接收到,就会发生异常,然后执行回滚事务channel.txRollback,然后重新发送消息即可,如果收到了消息,就执行提交事务channel.txCommit

// 开启事务
channel.txSelect
try {
    // 这里发送消息
} catch (Exception e) {
    channel.txRollback
 
    // 这里再次重发这条消息
}
 
// 提交事务
channel.txCommit

这个方法产生的问题是,如果使用事务机制,吞吐量就会下降,耗费性能

第二种方法是开启RabbitMQ的confirm模式,在生产者那里开启confirm模式之后,每次发送的消息都会附加消息id,如果RabbitMQ收到消息,就会回传一个ack消息,表示已经收到该消息了,如果RabbitMQ没有收到消息,就会回调nack接口,告诉生产者没有收到消息,生产者就可以重新发送。

事务机制和confirm模式最大的区别在于,事务机制是同步的,开启事务的时候会发生阻塞,不能发送下一个消息,而confirm模式是异步的,发送一个消息之后还可以紧跟发送下一个消息,RabbitMQ会异步通知生产者是否接收到消息

RabbitMQ丢失数据

可以通过开启RabbitMQ持久化的方法保证可靠性,消息写入之后会持久化到磁盘中,就算如果消息丢失,还可以恢复之前存储的消息。如果在持久化之前发生消息丢失,可能会丢失小部分数据,不过这个概率是极小的
开启持久化的步骤

  • 创建queue的时候开启持久化,可以保证持久化queue的元数据,不会持久化queue里面的数据
  • 发送消息的时候将消息的deliveryMode设置为2,这样消息也可以持久化到磁盘上

必须同时开启上面两个步骤,这样如果RabbitMQ挂掉,就可以通过磁盘恢复queue,queue中的数据也可以恢复

虽然在持久化到磁盘之前发生数据丢失的概率极小,但为了避免这个问题,我们可以将RabbitMQ持久化和confirm模式结合起来,只有消息持久化到磁盘之后才会向生产者发送ack,这样在在持久化之前发生数据丢失是不会发送ack的,生产者就会重发消息

消费者丢失数据

消费者在消费消息之后,还没来得及处理,进程就挂了,这样就会发送数据丢失

这个时候可以使用RabbitMQ的ack机制,需要关闭RabbitMQ的自动ack机制,使用自己写的api来调用ack机制,每次只有确保处理完消息之后才向RabbitMQ发送ack,如果RabbitMQ没有收到ack,就会把这条消息分配给其他消费者处理

Kafka

消费者丢失数据

当消费者消费了消息,但在处理之前就自动提交了offset,Kafka就会认为消费者已经处理完这个消息了,这时如果消费者挂了,这个数据就丢失了

此时只要我们关闭Kafka自动提交offset这个机制,然后等处理完消息之后手动提交一下offset就可以了,但是这样可能会出现重复消费的问题,消费完还没处理就挂了,还没提交offset,之后就需要再消费一次,这时我们只需要再保证一下幂等性就好了

Kafka 弄丢了数据

比如Kafka某个leader挂了,这时肯定要重新选举出一个leader,但此时follower刚好还没有同步leader的数据,结果让某个follower重新选举为leader之后就会少一些数据

所以这时我们必须要设置4个参数

  • 给 topic 设置replication.factor参数:这个值必须大于1,要求每个partition必须有至少2个副本
  • 在 Kafka 服务端设置min.insync.replicas参数:这个值必须大于1,要求一个 leader 至少感知到有至少一个 follower还跟自己保持联系,没掉队,这样才能确保leader挂了还有一个follower也存有全部数据
  • 在producer端设置acks=all:这个是要求每条数据,必须是写入所有replica之后,才能认为是写成功了
  • 在 producer 端设置retries=MAX(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里

对以上4个参数设置完毕后,就能保证如果leader挂了,重新选举leader也可以存有全部数据了

生产者会不会弄丢数据

如果按照上面4个参数那样设置了retries=MAX,是一定不会丢失数据的,要求是,leader接收到消息,所有的follower都同步到了消息之后,才认为本次写成功了,如果没满足这个条件,生产者会自动不断的重试,重试无限次。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值