1、kafka的存储机制
- 分区,就是kafka对应存储目录下创建的文件夹,文件夹的名字是主题名加上分区编号,编号从0开始
- segment,就是在分区对应的文件夹下产生的文件。一个分区会被划分成大小相等的若干segment。这样一方面保证了不会产生体积过大的文件, 另一方面可以基于这些segment文件进行历史数据的删除来提高效率。
- 读取指定分区中某个offset对应的数据过程如下:
- 先根据offset和当前分区的所有segment的文件名称做比较,确定数据在哪个segment中
- 查找该segment的索引文件,确定当前offset在数据文件中的开始位置
- 从该位置开始读取数据文件,再根据数据格式判断结果,最终获取到完整数据
2、消费者读取数据的可靠性
- kafka中保证数据一致的机制
在Kafka中维护了一个AR列表,包括所有的分区的副本,AR = ISR + OSR
只有 ISR 内的副本都同步了leader中的数据,该数据才能被提交,然后被消费者访问。OSR 内的副本是否同步了leader的数据,不影响数据的提交,OSR内的follower会尽力同步leader,可能数据版本会落后
最开始所有的副本都在ISR中,在kafka工作的过程中,如果某个副本同步速度慢于replica.lag.time.max.ms指定的阈值,则被踢出 ISR 并存入 OSR 队列。如果后续速度恢复可以回到 ISR 队列中。
- 严格模式和非严格模式
如图所示,若此时0号机器宕机了,在严格模式下,此时kafka集群只能提供读的服务。只有当0号机器活过来,才能提供写的服务。在非严格模式下,则会从OSR队列中选一个出来到ISR中。
可以发现,kafka并没有像zookeeper那么追求数据一致性,可以在数据一致性和可用性上自己选择。例如非严格模式下,可能出现丢数据的情况。
- HW,LEO标志位
在zookeeper里为每一个分区都记录了HW和LEO的信息,只有写入的数据被同步到ISR队列中的所有副本后,数据才认为已提交,HW才会更新到该位置,消费者只能访问到HW标志位之前的数据。
LEO标志位则表示目前最新数据的位置,HW到LEO的这部分数据,表示还在提交的数据。
- HW截断机制
- 当leader挂掉后,会从ISR队列中选出一个当新的leader。为了保证数据的一致,需要把HW标志位以后的数据全部干掉
- 当挂掉的leader复活后,也需要把HW之后的数据全部干掉,然后再同步当前leader的数据
如下图,当leader挂掉,ISR队列中还剩下follower1,follower2.。此时若follower2被选为leader,则follower1需要把数据‘D’清掉,才能保证和当前leader的数据一致。
3、生产者的生产数据的可靠性
- 生产者向leader发送数据时,可以通过request.required.acks参数配置,选择需要的可靠性级别
0 | 生产者不停向leader发送数据,而不需要leader反馈成功消息。这种模式效率最高,可靠性最低 |
1(默认) | 生产者发送数据给leader,leader收到数据后返回成功ACK,生产者收到ACK后认为发送数据成功 。如果一直收不到成功消息,则生产者会自动重发数据. 当leader宕机时,可能丢失数据 |
2 | 生产者发送数据给leader,leader收到数据后要等到ISR列表中的所有副本都同步数据完成后,才向生产者发送ACK,如果一直收不到ACK,则会自动重发数据. 可以通过配置min.insync.replicas指定要求观察ISR中至少要有指定数量的副本,默认该值为1,需要改为大于等于2的值。这样当生产者发送数据给leader但是发现ISR中只有leader自己时,会收到异常,表明数据写入失败 |
- 如果去除重复数据
kafka实现了给消息带上唯一编号的组件,但是去重的组件并未实现。
所有生产者发送消息时,需要附带上一个唯一编号。而重发消息的时候,对应的编号是不能改变的。这样leader就可以判断这个消息是否是重复的,只存一个即可。但是,怎么判断这个消息是否是重复并去重,这一部分kafka并未实现,这个交给开发人员后面使用时根据自己的业务去处理。
所以kafka只能做到不丢会多这个程度。
4、Leader选举
当leader宕机时 会选择ISR中的一个follower成为新的leader,如果ISR中的所有副本都宕机怎么办?可以通过配置来选择处理方式:
unclean.leader.election.enable=false | 必须等待ISR列表中的副本活过来才选择其成为leader继续工作。 可靠性有保证,但是可用性低,只有最后挂了leader活过来kafka才能恢复 |
unclean.leader.election.enable=true | 选择任何一个活过来的副本(可能不在ISR中)成为leader继续工作 可用性高,可靠性没有保证,任何一个副本活过来就可以继续工作,但是有可能存在数据不一致的情况 |