kafka读书笔记

必须要去读的

https://github.com/dvsusan/susanSayJava
Kafka系列9:面试题是否有必要深入了解其背后的原理?我觉得应该刨根究底

会遇到的问题

重复消息问题
数据一致性问题
消息丢失问题
消息顺序问题
消息堆积

kafka源码

Kafka源码的总览

初识kafka

在这里插入图片描述

分区中所有副本统称为AR(Assigned Replicas),所有与leader副本保持一定程度同步的副本(包括leader副本本身)称为ISR(In-Sync Replicas),ISR集合是AR集合的子集,生产者发消息到broker时会将消息先发送到leader副本,然后follower副本从leader副本中拉取消息进行同步,与leader副本同步滞后过多的副本组成OSR(Out-of-Sync Replicas),所以AR= ISR + OSR,正常情况下,ISR = AR。ISR与HW(high watermark),LEO(log end offset)有紧密的关系,HW称为高水位,它标识了一个特定的消息偏移量,消费者只能拉取到这个offset之前的消息,LEO标识着当前分区日志文件的下一条待追加的消息的offset,分区ISR集合中的每个副本都会维护自身的LEO,而ISR集中中最小的LEO即为分区的HW,对消息费者而言只能消费到HW之前的消息。

如图所示,它代表一个日志文件,这个日志文件中有 9 条消息,第一条消息的 offset(LogStartOffset)为0,最后一条消息的offset为8,offset为9的消息用虚线框表示,代表下一条待写入的消息。日志文件的HW为6,表示消费者只能拉取到offset在0至5之间的消息,而offset为6的消息对消费者而言是不可见的。

在这里插入图片描述
LEO是Log End Offset的缩写,它标识当前日志文件中下一条待写入消息的offset,图中offset为9的位置即为当前日志文件的LEO,LEO的大小相当于当前日志分区中最后一条消息的offset值加1。分区ISR集合中的每个副本都会维护自身的LEO,而ISR集合中最小的LEO即为分区的HW,对消费者而言只能消费HW之前的消息。

为了更好地理解ISR集合,以及HW和LEO之间的关系,下面通过一个简单的示例来进行相关的说明。如图所示,假设某个分区的ISR集合中有3个副本,即一个leader副本和2个follower副本,此时分区的LEO和HW都为3。消息3和消息4从生产者发出之后会被先存入leader副本

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

由此可见, kafka 的复制机制既不是完全的同步复制,也不是单纯的异步复制。事实上,同步复制要求所有能工作的 follower 副本都复制完,这条消息才会被确认为已成功提交,这种复制方式极大地影响了性能。而在异步复制方式下, follower 副本异步地从 leader 副本中复制数据,数据只要被 leader 副本写入就被认为已经成功提交。在这种情况下,如果 follower 副本都还没有复制完而落后于 leader 副本,突然 leader 副本宕机,则会造成数据丢失。 Kafka 使用的这ISR 的方式则有效地权衡了数据可靠性和性能之间的关系。

AR、ISR、HW、LEO相关概念

  • 副本是相对于分区而言的 ,即副本是特定分区的副本。
  • 一个分区中包含一个或多个副本,其中一个为 leader 副本,其余为 follower 副本,各个副本位于不同的 broker 节点中。只有 leader 副本对外提供服务, follower 副本只负责数据同步。
  • 分区中的所有副本统称为AR,而ISR 是指与 leader 副本保持同步状态的副本集合,当然 leader 本本身也是这个集合中的一员。
  • LEO 标识当前日志文件中下一条待写入的消息的offset,分区的每个副本都有自己的LEO,ISR中最小的LEO即为HW ,俗称高水位,消费者只能拉取到 HW之前的消息。

生产者发出的一条消息首先会被写入分区的 leader 副本,不过还需要等待 ISR 集合中的
所有 follower 副本都同步完之后才能被认为已经提交,之后才会更新分区的 HW ,进而消费者
可以消费到这条消息。

kafka如何保证消息的可靠性

kafka消息丢失解决方案
在这里插入图片描述

Kafka 会不会丢消息?怎么处理的?
在这里插入图片描述
brock可能丢:

kafka为保证高性能,brock刷盘采取了异步刷盘,即批量将数据先存在page cache中,然后调linux的fsync函数落盘,这时如果系统掉电,数据丢失。(异步方式:produer只管发,不需要等待brock的响应,rocketmq实现了同步:你发一条消息就需要等待我完全落盘,放回success,再发下一条)。那kafka如何解决异步可能丢消息的了—尽最大努力,通过producer和brocker配合:设置了ack机制:(0,1,-1)

producer可能丢:
异步发送:数据在等待发送时,是有丢失风险的。-----阻塞,丢弃?

consumer可能丢:
自动提交方式:比如每1000ms提交一次,但我拉取消息,处理消息就花了1000ms,到我入数据库失败了,但消息处理已经提交了,这时消息就丢了

手动提交:可以保证消息至少消费一次,但可能存在消息重复消费

kafka重复消费问题

说实话,使用kafka问题挺多的,重复消息至少其中一个问题
从真实业务讲解

Kafka重复消费的原因及解决方案------短链接的经典应用

kafka重复消费问题
【5秒的断电,5分钟后的rebalance】
kafka brocker上存储的消息,都有一个offset标记, kafka的消费者是通过这个标记,来维护当前已经消费的一个数据,消费者每消费一批数据呢,brocker就会更新offset的一个值,避免重复消费的一个问题,默认情况下消息消费完成以后,会自动提交offset这样一个值,避免重复消费,消费端的这个自动提交机制会有一个五秒的间隔,5秒之后的下一次向broker去获取消息的时候,来实现一个offset提交,所以在consumer的消费过程中,应用程序强制被kill掉或者宕机的过程, 可能会导致offset没有提交,从而产生重复消费的一个问题,除此之外,还有另外一种情况也会导致重复消费

有一个叫partition balance的一个机制,就是把多个partition均衡的分配给多个消费者,comsumer端会从分配的partition里面去消费消息,如果comsumer在默认的五分钟内,没办法,处理完这一批消息的时候,就会触发kafka的rebalance机制,从而导致offset自动提交失败,而在重新rebalance以后,comsumer端还是会从之前的没有提交的offset的位置,开始去消费,从而导致重复消费的问题。在这样的背景下,解决重复消费的方法有

1.提高消费端的处理性能,避免触发rebalance(可以用异步的方式处理消息,缩短单个消息的消费时长),
2.调整消费端消息处理的一个超时时间(把它拉长一点)
3.减少一次性从broker上获取消息的条数
4.针对每个消息生成一个md 5的值保存到mysql或者redis中,在处理消息之前,先去数据库中查看是否有被消费过(该方法其实就是利用幂等性的思想去实现的)
重复消费的问题,如果没有考虑到,就会出现线上数据问题

为什么五分钟没有消费完消息就会触发rebance:
kafka的批量提交机制,默认5分钟下游端要消费500条数据,如果消费不到,kafka会认为你的consumer已经死了,然后会从批量提交过的位置rebalance,就是重新发一遍消息到consumer,原始的数据也不会清除,这就导致重复消费,这个问题我在生产环境遇到过,所以重逻辑处理用Kafka真是坑到家了

:很简单,将时间间隔设长或者消费条数变少,或者关闭自动提交,手动ack就行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值