Kafka介绍与原理分析
kafka是什么?
简介
Apache Kafka 是一款高吞吐量的分布式的基于发布/订阅模式的消息系统,主要应用于大数据实时处理领域。它使用Scala和Java语言编写,是一个基于Zookeeper系统的分布式发布订阅消息系统,该项目的设计初衷是为实时数据提供一个统一、高吞吐量、低等待的消息传递平台。在0.10版本之前,Kafka只是一个消息系统,主要用来解决应用解耦、异步消息等问题。
kafka一般被称为“分布式提交日志”或者“分布式流平台”。文件系统或数据库提交日志用来提供所有事务的持久记录,通过重放这些日志可以重建系统的状态。同样地,Kafka 的数据是按照一定顺序持久化保存的,可以按需读取。此外,Kafka 的数据分布在整个系统里,具备数据故障保护和性能伸缩能力。
logo核心能力
-
高吞吐量:即使在非常廉价的商用机器上也能做到单机支持每秒数百万消息的传输。使用延迟低至 2 毫秒的机器集群以网络有限的吞吐量传递消息。
-
消息持久化:以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间复杂度的访问性能
-
分布式:支持消息分区以及分布式消费,并保证分区内的消息顺序。
-
伸缩性:系统可以随着数据流的增长进行横向扩展。可将生产集群扩展到多达一千个代理、每天数万亿条消息、PB 级数据、数十万个分区,弹性扩展和收缩存储和处理。
-
跨平台:支持不同技术平台的客户端(如Java、PHP、Python等)。
-
实时性:支持实时数据处理和离线数据处理。
发布/订阅模式
一对多,消费者消费数据之后不会清除消息
消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到 topic 的消息会被所有订阅者消费。
发布/订阅模式基础架构
img-
Producer : 消息生产者,负责向 Kafka 发送消息到broker中。一般情况下,一个消息会被发布到一个特定的主题上。生产者在默认情况下把消息均衡地分布到主题的所有分区上,而并不关心特定消息会被写到哪个分区。
-
Consumer : 消息消费者,向 Kafka broker 读取消息的客户端。消费者订阅一个或多个主题,并按照消息生成的顺序读取它们。消费者通过检查消息的偏移量来区分已经读取过的消息。
-
Consumer Group (CG): 消费者组,若干个Consumer组成的集合。 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。 所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
-
Broker :经纪人,一台 独立的Kafka 服务器就是一个 broker。broker 接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。broker 为消费者提供服务,对读取分区的请求作出响应,返回已经提交到磁盘上的消息。一个集群由多个 broker 组成。一个 broker可以容纳多个 topic。
-
Topic : 主题,kafka中的消息都是通过主题进行分类的,可以理解为一个队列, 生产者和消费者面向的都是一个 topic。主题可以被分为若干个分区,一个分区就是一个提交日志。消息以追加的方式写入分区,然后以先入先出的顺序读取。
-
Partition: 为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。;
-
Replica: 副本(Replication),为保证集群中的某个节点发生故障时, 该节点上的 partition 数据不丢失,且 Kafka仍然能够继续工作, Kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower。
-
Leader: 每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 leader。
-
Follower: 每个分区多个副本中的“从”,实时从 leader 中同步数据,保持和 leader 数据的同步。 leader 发生故障时,某个 Follower 会成为新的 leader。
工作原理分析
生产消息流程
producer是消息的生产者,也就是数据的入口。producer在写入数据的时候永远都是找leader,而不会直接将数据写入follower中。
-
producer推送消息前,会先从集群中获取分区的leader信息。
-
producer将消息推送给相应的leader。
-
leader将收到的消息追加到本地文件的末端,且每条都有自己的offset。
-
follower主动的从leader中拉取消息进行同步。
-
follower将消息写入到本地中,然后想leader发送ack。
-
leader收到所有follower的ack后,确保同步完成,再向producer发送ack。producer收到ack后就会进行下一轮的推送,否则重新推送消息。
副本数据同步策略
序号 | 方案 | 优点 | 缺点 |
---|---|---|---|
1 | 半数以上完成同步, 就发送 ack | 延迟低 | 选举新的 leader 时,容忍 n 台节点的故障,需要 2n+1 个副本。(如果集群有2n+1台机器,选举leader的时候至少需要半数以上即n+1台机器投票,那么能容忍的故障,最多就是n台机器发生故障)容错率:1/2 |
2 | 全部完成同步,才发送ack | 选举新的 leader 时, 容忍 n 台节点的故障,需要 n+1 个副本(如果集群有n+1台机器,选举leader的时候只要有一个副本就可以了)容错率:1 | 延迟高 |
Kafka 选择了第二种方案,原因如下:
-
同样为了容忍 n 台节点的故障,第一种方案需要 2n+1 个副本,而第二种方案只需要 n+1 个副本,而 Kafka 的每个分区都有大量的数据, 第一种方案会造成大量数据的冗余。
-
虽然第二种方案的网络延迟会比较高,但网络延迟对 Kafka 的影响较小。
文件存储机制
img由于生产者生产消息会不断的追加数据到log文件末尾,为防止log文件过大导致数据定位效率低下,kafka采用了分片和索引机制,将每个partition分为多个segment。
每个segment对应两个文件“.index” 和 “.log”文件,这些文件位于一个文件夹下,该文件的命名规则为:topic名称+分区序号。例如,first这个topic有3个分区,分别为first-0、first-1、first-2。
00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
00000000000000239430.index
00000000000000239430.log
index和log文件以当前segment的第一条信息的offset命名。
".index"文件存储大量的索引信息, ".log"文件存储大量的数据,索引中的元数据指向对应数据文件中的message的物理偏移地址。
img生产者
分区策略
分区原因
-
方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,而一个 Topic 又可以有多个 Partition 组成,因此整个集群就可以适应适合的数据了。
-
可以提高并发,因此可以以 Partition 为单位读写了。
分区原则
-
指明 partition 的情况下,直接将指明的值直接作为 partiton 值;
-
没有指明 partition 值但有 key 的情况下,将 key 的 hash 值与 topic 的 partition 数进行取余得到 partition 值;
-
既没有 partition 值又没有 key 值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与 topic 可用的 partition 总数取余得到 partition值,也就是常说的 round-robin 算法。
AR、LSR、OSR
AR:分区中的所有副本统称为AR(Assigned Repllicas)。
ISR:所有与leader副本保持一定程度同步的副本(包括Leader)组成ISR(In-Sync Replicas),ISR集合是AR集合中的一个子集。消息会先发送到leader副本,然后follower副本才能从leader副本中拉取消息进行同步,同步期间内follower副本相对于leader副本而言会有一定程度的滞后。
OSR:与leader副本同步滞后过多的副本(不包括leader)副本,组成OSR(Out-Sync Relipcas)
由此可见:AR=ISR+OSR。在正常情况下,所有的follower副本都应该与leader副本保持一定程度的同步,即AR=ISR,OSR集合为空。
Leader副本负责维护和跟踪ISR集合中所有的follower副本的滞后状态,当follower副本落后太多或者失效时,leader副本会吧它从ISR集合中剔除。 如果OSR集合中follower副本“追上”了Leader副本,之后再ISR集合中的副本才有资格被选举为leader,而在OSR集合中的副本则没有机会(这个原则可以通过修改对应的参数配置来改变)
AR=ISR+OSRack机制
对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等 ISR 中的 follower 全部接收成功。
所以 Kafka 为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡,选择以下的配置。
acks 参数配置:
-
0: producer 不等待 broker 的 ack,这一操作提供了一个最低的延迟, broker 一接收到还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据;
-
1: producer 等待 broker 的 ack, partition 的 leader 落盘成功后返回 ack,如果在 follower同步成功之前 leader 故障,那么将会丢失数据;
-
-1(all) : producer 等待 broker 的 ack, partition 的 leader 和 ISR 的follower 全部落盘成功后才返回 ack。但是如果在 follower 同步完成后, broker 发送 ack 之前, leader 发生故障,那么会造成数据重复。
助记:返ACK前,0无落盘,1落盘,-1全落盘,(落盘:消息存到本地)
数据一致性
-
LEO:(Log End Offset)每个副本的最后一个offset
-
HW:(High Watermark)高水位,指的是消费者能见到的最大的 offset, ISR 队列中最小的 LEO
消息都正常同步的情况,leader和follower的水位一致,LEO和HW都保存一致。
producer写入消息producer现在往leader中写入消息4和5,leader的LEO与follower发生不对称。
follower同步消息在消息写入leader之后,follower会发送拉取请求来拉取消息4和消息5以进行消息同步。其中在同步过程中,不同的 follower 的同步效率也不尽相同。在某一时刻follower1完全跟上了leader而follower2只同步了消息4,如此leader的LEO为6,follower1的LEO为6,follower2的LEO为5,那么当前分区的HW取最小值4,此时消费者可以消费到offset为0至4之间的消息。
同步完成当所有的副本都成功写入了消息3和消息4,整个分区的HW和LEO都变为6,因此消费者可以消费到offset为5的消息了。
follower 故障和 leader 故障
-
follower 故障:follower 发生故障后会被临时踢出 ISR,待该 follower 恢复后, follower 会读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 leader 进行同步。等该 follower 的 LEO 大于等于该 Partition 的 HW,即 follower 追上 leader 之后,就可以重新加入 ISR 了。
-
leader 故障:leader 发生故障之后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性, 其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader同步数据。
注意: 这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。