在使用MQ的时候,怎么确保消息100%不丢失

首先,一条消息从生产到消费整个过程,可以分为三个阶段;

分别为:消息生产阶段、消息存储阶段、消息消费阶段;

一、生产者到broker消息丢失:

从消息被生产出来,然后提交给mq的过程中;生产者发送消息到broker是会存在消息丢失的;

丢失原因:

1、网络波动导致没有回调;

2、数据消息太大超出broker承受范围,导致broker拒收消息等;

3、kafka默认ack设置为1,会存在数据丢失问题;

解决方案:

1、更换调用方式,不使用异步发送,使用带回调通知函数的方法进行发送消息;

2、对于消息发送失败,可以调整producer端重试次数和消息大小;

3、修改ack设置为-1;(可以结合幂等性做到端到端一致)

acks有三种类型:0、1、-1(all);

ack设置为0,代表生产者发送消息后就不管了,不用等待broker的任何响应,这样可能导致消息丢失;

ack设置为1,代表生产者发送消息到broker后,只需要broker的leader副本确认收到后就成功响应,不需要follower副本响应,就算follower副本崩溃了,也会成功响应;

ack设置为-1,或者all,那么生产者发送消息需要leader和follower都收到并写入消息才成功响应生产者,需要至少两个以上副本;

ps:生产者重试发送消息,可以手动在代码中编写消息重发逻辑,也可以配置kafka重试参数retries(重试次数),retry.backoff.ms(重试时间间隔);

消息重发引起的消息顺序性问题,如果服务对于消息的顺序性有严格要求,可以通过设置属性max.in.flight.requests.per.connection=1来保证消息的顺序性;

二、broker到磁盘消息丢失:

这个阶段一般直接交给MQ消息中间件来保证,Broker会做副本,保证一条消息至少同步两个节点再返回ack;

丢失原因:

数据从生产者push过来后,broker端需要将数据持久化存储到磁盘中;

消息存储是异步存储的,即按照一定的消息数量和间隔时间进行存储,数据会先放在pageCache中;

如果在存储的时候broker宕机,此时选举了一个落后Leader Partition很多的Follower Partition成为新的Leader Partition,那么落后的消息就会丢失;

解决方案:

修改参数,

1、设置有资格成为Leader的Follower(不要落后的太久),设置分区数>=3(Leader宕机后可以由Follower补上);

2、设置ack为-1,至少写入两个副本才算成功;

三、消费者消息丢失:

kafka的消费模式是拉模式,需要不断地向broker拉取消息,拉取的消息消费了以后需要提交offset,这里可能会出现丢消息;

丢失原因:

1、设置为自动提交offset,当消息处理过程中发生异常,则下次获取消息的时候,之前的消息就获取不到了;

2、拉取消息后,先提交offset,再处理消息,如果处理消息的时候宕机,则之前未处理的消息不会再次处理;

解决方案:

使用手动提交位移的方式,设置参数enable.auto.commit=false且处理顺序为:先拉取消息,再处理消息,再提交offset;

以上阶段,每个阶段都能保证消息的不丢失,但在分布式系统中,故障无可避免,作为消费生产端,我们并不能保证mq是不是弄丢了你的消息,消费者是否消费了你的消息,所以,还可以设计一种机制,来检查消息是否丢失;

方案思路为:

在消息生产端,给每个发出的消息都指定一个全局唯一id,或者附加一个连续递增的版本号,然后在消费端做对应的版本效验;在生产端发送消息之前,通过拦截器将消息版本号注入消息中(版本号可以采用连续递增的id生成,也可以通过分布式全局唯一id生成)。

在消费端收到消息后,再通过拦截器检测版本号的连续性或消费状态,这样实现的好处是消息检测的代码不会侵入到业务代码中,可以通过单独的任务来定位丢失的消息,做进一步的排查;全局唯一id生成的实现方式有数据库自增逐渐、UUID、Redis等;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值