1.选举Leader
Leader 是 Partition 级别的,当一个 Broker 挂掉后,所有 Leader 在该 Broker 上的 Partition 都会被重新选举,选出一个新 Leader。
Kafka 先使用 ZooKeeper 在 Broker 中选出一个 Controller,用于上述 Partition分配和 Leader 选举。
Controller 会在 ZooKeeper 的 /brokers/ids 节点上注册 Watch 监听,一旦有 Broker 宕机,Controller就收到通知。
Partition 分配:
- 将所有 Broker(假设共 n 个 Broker)和待分配的 Partition 排序。
- 将第 i 个 Partition 分配到第(i mod n)个 Broker 上 (这个就是 Leader)。
- 将第 i 个 Partition 的第 j 个 Replica 分配到第((i + j) mode n)个 Broker 上。
Leader 选举:
Controller 从 ZooKeeper 的 /brokers / topics / [topic名称] / partitions / [partition名称] / state 中,读取对应 Partition 的 ISR(in-sync replica 已同步的副本)列表,选一个出来做 Leader。
ISR 列表中的机器是会变化的,根据配置 replica.lag.time.max.ms,多久没同步,就会从 ISR 列表中去除。
0.10版本之前,还有个参数是根据落后多少条消息就踢出 ISR,在 0.10 版本后就去掉了,因为这个值很难取,在高峰的时候很容易出现节点不断的进出 ISR 列表的情况。
选出 Leader 后,更新 ZooKeeper,然后Controller发送 LeaderAndISRRequest 给受影响的 Broker,通知所有相关Broker:新leader已产生。
选举完成之后,所有对某个 Partition 的请求,实际操作的都是 Leader,然后其他 Follower 再 Pull 消息同步。
2.Partition的分发策略:
- Partition 在写入的时候可以指定需要写入的 Partition,如果有指定,则写入对应的 Partition。
- 如果没有指定 Partition,但是设置了数据的 Key,则会根据 Key 的值 Hash 出一个 Partition。
- 如果既没指定 Partition,又没有设置 Key,则会轮询 各个Partition。
3.Partition文件:
Partition 在操作系统中就是一个个的文件夹,每个 Partition 的文件夹下面会有多组 Segment 文件。
每组 Segment 文件又包含 .index 文件、.log 文件、.timeindex 文件(早期版本中没有)三个文件。
Log 文件就是实际存储 Message 的地方,而 Index 和 Timeindex 文件为索引文件,用于检索消息。
文件的命名是以该 Segment 最小 Offset 来命名的,如下图中间那个segment的命名是 368796.index, 存储了Offset 为 368796~1105813 的消息。
建立在 Offset 为有序的基础上,Kafka利用 Segment分段文件记录+Segment文件内索引+有序Offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据。
在0.10版本前,消费者将消费到的 Offset 维护在 Zookeeper 中,Consumer 每间隔一段时间上报一次,容易导致重复消费,且性能不好;
0.10版本后,消费者消费到的 Offset 已经直接维护在 Kafka 集群的 __consumer_offsets 这个Topic 中。