Kafka数据不丢失的策略权衡

一、会丢数据的情况

1、生产端

可通过 producer.type 来选择发送模式,默认为 producer.type = sync (同步),异步设置为 async

1)同步模式下

Producer 在发送消息之后,在得到返回结果前阻塞。这是一种牺牲性能的办法,而且对于不同的配置,性能的损失程度不同、可靠性也不一样。关键参数如下

request.required.acks 表示producer的一次请求被认为是完成时,需要的 ack 确认数,这里的 ack 具体是指哪些 broker 已经提交消息到log日志文件中。

为 0 时表示不需要等待来自broker的确认信息,可实现最大的吞吐量,但是这种发出去就不管了的方式可能会丢失数据。因为 message 放入 socket buffer 即认为已经发送,没有任何机制来保证broker成功接收数据。重试机制也不会起作用。

为 1 时表示等 leader 所在 broker 已经成功将消息写入到本地log中返回确认即可,但是如果 leader 返回确认后,fllower 还没有来的及从leader同步message而 leader 就挂掉了,此时也会丢数据。

为 -1 时 producer 会获得leader及所有同步replicas都收到数据的确认,同步replicas数由 min.insync.replicas 确定。

2)异步模式下

异步发送模式下,可以批量处理请求,消息先被填入缓冲区当中,当达到 batch.size 时或者达到 linger.ms 配置的等待时间发送缓冲区数据到broker。

这种情况下,如果客户端挂了,那么便会丢失未发送数据。

2、消费端

enable.auto.commit=true

一般情况下,自动提交offset默认为true,也就是在consumer拉取一批数据时会自动提交最新的消费偏移给kafka,表示我已经消费到哪里了。

这样的话,如果consumer拉取并提交了最新的 offset ,而 consumer 当前的message还没有处理完,这时consumer挂了,恢复时从最新提交的 offset 处理,这么一来便丢失了数据。

解决这个问题,可以在消息处理完成后手动提交 offset。

3、broker

unclean.leader.election.enable = true 从Kafka 0.11.0.0 之后 默认值改为了 false

这个参数确定了什么事呢?也就是确定不在同步副本当中的broker是否可以参与新leader的选举

1)参与

如果在ISR中的同步副本同时下线,这时如果unclean.leader.election.enable = true,那么不在ISR中的副本就可以参与选举,此时机器还是可用的。

但是一个问题是,不在ISR中的副本,其偏移会落后于ISR中的副本,当其成为leader之后,接收来自客户端的消息。之前下线的leader恢复之后成为follower,去新的leader同步消息,发现自己的Log End Offset大于新leader的Log End Offset,必须进行截断(follower不能比leader的LEO大),此时便造成了丢数据和不一致的情况。

2)不参与

如果unclean.leader.election.enable = false,那么不在ISR中的副本就不可以参与选举,此时如果在ISR中的同步副本同时下线,kafka服务便不可用了。

4、刷盘方式

1)同步刷盘

写入页缓存,线程等待,通知刷盘线程刷盘,刷盘线程刷盘后,唤醒前端等待线程,等待线程向用户返回写入结果,也就是进行ack

可见,同步等待落盘后确认,不会出现掉电数据未刷盘的情况,但对性能的影响是显而易见的

2)异步刷盘

写入页缓存,线程返回,向用户返回写入结果,刷盘由操作系统完成

如果线程返回ack,而broker所在节点突然掉电导致页缓存未刷盘,就丢失了数据。

和主动刷盘相关的几个配置
log.flush.interval.messages 设置刷盘前在内存中最多累积的消息数
log.flush.interval.ms 设置消息在刷盘之前最多在内存中保存的ms数
log.flush.scheduler.interval.ms 设置log flusher线程检查是否有消息需要刷盘的检查频度

在kafka中,数据可靠性主要靠分布式副本冗余来完成,避免单点故障,所以不出现极端的情况,异步刷盘也没有问题。

总之,万事无绝对,性能和可靠性之间总是要进行权衡,根据需要来进行选择吧。

你可能感兴趣的:(Kafka)