【消息队列】kafka如何保证消息不丢失?

在这里插入图片描述

👏大家好!我是和风coding,希望我的文章能给你带来帮助!
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
📝点击 我的主页 还可以看到和风的其他内容噢,更多内容等你来探索!
📕欢迎参观我的个人网站:Gentlewind

在这里插入图片描述



kafka 的架构

kafka 的架构非常简洁,主要是分布式架构,由 Producer、Broker、Consumer 组成。

🔊所以分析丢失的场景也会由这三部分来进行。

从 Kafka 整体架构图我们可以得出有三次消息传递的过程:

1)Producer 端发送消息给 Broker 端。

2)Broker 将消息进行同步并持久化数据。

3)Consumer 端从 Broker 将消息拉取并进行消费。

消息语义传递

首先我们先了解一下保证消息传递的一个通信模型:消息语义传递

他有三个类型:

  1. At Most Once(最多一次):消息在传递过程中最多被传递一次。也就是说消息可能会丢失,但不会重复传递
  2. At Least Once(至少一次):消息在传递中至少传递一次。也就是消息不会丢失,但可能重复传递
  3. Exactly Once(恰好一次):也就是精确的传递一次。既不丢失,也不重复传递

我们需要**根据具体的场景,选择需要的传递类型。**比如对消息丢失不能忍受,但是可以接收消息重复传递,就可以选择第二种类型。

然后再根据需求来对 kafka 进行相应的配置。就类似于 CAP 理论,这是一个取舍问题。

Producer

Producer 端发送消息到 Broker 端,消息丢失的情况可能会有:

  • 网络波动导致消息没有发送到 Broker
  • 发送途中 Broker 宕机了
  • 消息太大超过了 Broker 的容量被拒收了

总结:丢失的原因就是消息根本没有发送到 broker 端

拓展:Producer 端为了提升发送效率,减少IO操作,发送数据的时候是将多个请求合并成一个个 RecordBatch,并将其封装转换成 Request 请求「异步」将数据发送出去(也可以按时间间隔方式,达到时间间隔自动发送)

解决方案:

  1. ACK 机制

可以通过配置 ack 来对消息进行确认,进而保证消息不丢失。

具体 ack 的配置为:

  • acks = 0:不进行确认,也就是实现第一种类型
  • acks = 1:消息发送到 broker 的分区后进行一次 ack 确认,确认接收成功后就完成了。但是它只保证了发送消息到主分区。如果从分区还没有同步完数据而主分区宕掉了,就会造成丢数据。
  • acks = all:对所有的主从分区进行 ack 确认,都成功接收消息才完成。这样的可靠性最高,但是相应的吞吐率也会更低。

其实就是同步的方式,Producer要保证消息到达服务器,就需要使用到消息确认机制,也就是说,必须要确保消息投递到服务端,并且得到投递成功的响应,确认服务器已接收,才会继续往下执行。

Broker

kafka 中,broker 接收到消息会先存放在 Pagecache (缓存)中,然后通过批量异步刷盘的策略来对数据进行同步和持久化。

Broker 将消息进行同步并持久化数据。消息丢失的情况有:

  • 当刷盘之前 broker 宕掉了,然后推举出了一个落后数据的从分区。那么之前的数据就丢失了

解决方案:

  1. 同步刷盘:可以通过一些配置实现同步刷盘,可以保证消息不丢失,这样就算失败,也可以进行及时补偿。

# 当达到下面的消息数量时,会将数据flush到日志文件中。默认10000

#log.flush.interval.messages=10000

# 当达到下面的时间(ms)时,执行一次强制的flush操作。interval.ms和interval.messages无论哪个达到,都会flush。默认3000ms

#log.flush.interval.ms=1000

# 检查是否需要将日志flush的时间间隔

log.flush.scheduler.interval.ms = 3000

同样可以达到同步刷盘的效果。

  1. kafka 默认通过「**多 Partition (分区)多 Replica(副本)机制」**已经可以最大限度的保证数据不丢失,如果数据已经写入 PageCache 中但是还没来得及刷写到磁盘,此时如果所在 Broker 突然宕机挂掉或者停电,极端情况还是会造成数据丢失。

Consumer

Consumer 消费消息有两个步骤:

  1. 从 broker 中拉取消息
  2. 处理消息,然后标记消息已经消费并提交 offset 记录(消息位移记录),下次继续消费的时候,会接着上次的offset进行消费。

那么 Consumer 端从Broker 将消息拉取并进行消费,可能丢失的场景有:

  • 开启了自动提交,如果开启了自动提交,那么系统会自动进行提交offset。可能会引起,并未消费掉,就提交了offset.引起数据的丢失。

  • 并且自动提交也分两种情况:

    • 拉取消息后「先提交 Offset,后处理消息」,如果此时处理消息的时候异常宕机,由于 Offset 已经提交了, 待 Consumer 重启后,会从之前已提交的 Offset 下一个位置重新开始消费, 之前未处理完成消息不会被再次处理,对于该 Consumer 来说消息就丢失了。

    • 拉取消息后「先处理消息,在进行提交 Offset」, 如果此时在提交之前发生异常宕机,由于没有提交成功 Offset, 待下次 Consumer 重启后还会从上次的 Offset 重新拉取消息,不会出现消息丢失的情况, 但是会出现重复消费的情况,这里只能业务自己保证幂等性。

解决方案:

设置参数enable.auto.commit = false, 采用手动提交位移的方式。这样如果消费失败的情况下,我们可以不断地进行重试。所以,消费端不要设置自动提交,一定设置为手动提交才能保证消息不丢失。而幂等的问题可以在业务逻辑中进行判断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值