Kafka的高可用和高性能实现
Kafka高可用
1. 副本机制
副本机制会将一个broker下某个topic的一个partition放入到另外一个broker里,这个备份的分区和原分区都叫做副本(replica)。在所有的副本里,只能有一个leader,其余的副本都作为follower,同一时间内只有leader负责读写,follower不起任何作用。其他所有的follower会异步的拉取leader消息。当leader挂掉之后,为了保证高可用性,会从中选择一个副本作为leader。
Kafka高性能
1. 分区
Kafka将topic分区,每一个broker里面会保存topic的不同分区,这样就可以让一个消费者组同时消费不同的分区,提高吞吐。
2. 页缓存
Kafka将数据写入页缓存(内存)中而不直接操作磁盘,由操作系统决定什么时候把页缓存中数据刷到磁盘上。同时写入页缓存的数据是按照磁盘顺序去写入的,因此刷到磁盘上的速度也较快。当读操作发生时,先从页缓存中查询是否有所需信息,若没有才会调度磁盘。
3. 零拷贝——PageCache 结合 sendfile 方法
若页缓存中没有所需信息,需要去调度磁盘数据。一般网络io操作需要四个步骤 : 硬盘 -> 内核态 PageCache -> 用户态程序读取 -> 内核态socket写入 -> 拷贝至网卡。通过Sendfile优化后,使用零拷贝可以将buffer从内核态和用户态间任意切换。PageCache仅会传递一个文件描述符给socket,就等效于直接从PageCache中拷贝至网卡,从而少了两步IO操作。
Leader的选举
1. Leader宕机
如果Leader宕机了该怎么办?很容易想到在Follower中重新选举⼀个Leader,但是选举哪个作为leader呢?Follower可能已经落后许多了,因此要选择的是“最新”的Follower:新的Leader必须拥有与原来Leader commit过的所有信息。
kafka动态维护了⼀组同步leader数据的副本(ISR),只有这个组的成员才有资格当选leader。kafka副本写⼊不被认为是已提交,直到所有的同步副本已经接收才认为是。这组ISR保存在zookeeper,正因为如此,在ISR中的任何副本都有资格当选leader。
2. 如果Replica都死了怎么办
只要⾄少有⼀个replica,就能保证数据不丢失,可是如果某个partition的所有replica都死了怎么办?有两种⽅案:
(1)等待在ISR中的副本恢复,并选择该副本作为Leader;
(2)选择第⼀个活过来的副本(不⼀定在 ISR中),作为Leader
这里存在可⽤性和⼀致性的⽭盾:如果⼀定要等待副本恢复,等待的时间可能⽐较⻓,甚⾄可能永远不可⽤。如果是第⼆种,不能保证所有已经commit的消息不丢失,但有可⽤性。Kafka默认选⽤第⼆种⽅式,⽀持选择不能保证⼀致的副本。可以通过参数unclean.leader.election.enable禁⽤它。