Kafka在HA架设需要两个内容
Replication (主从复制)
Leader Election (从属选取主级)
在Kafka在0.8以前的版本中,是没有Replication(主从控制)的,一旦某一个Broker(服务器节点)宕机,则其上所有的Partition(topic分区)数据都不可被消费,这与Kafka数据持久性及Delivery Guarantee(消息消费保障的设计目标相悖。同时Producer(生产者)都不能再将数据存于这些Partition(topic分区)中。
一、如何进行Replication主从复制:
1、如何把replica均匀的分布到集群中的每一个或者大多数的节点上(broke)
可以从前面的文章回到一个事实,为了能够提高整个集群的性能需要吧同一个topic下面的所有partition尽可能的分布到整个集群上去,一个典型的解决方案就是topic的partition的数量大于broke的数量.同样的,为了提高卡夫卡的HA,我们需要吧同一个partitio下面的所有replica(备份)尽量的分散到不同的服务器上去.(事实上,如果我们把某一个partition的所有replica全部放到同一个broker上那么同样的这个broker宕机了,也就回到这这个partition下面的所有信息丢失,没有起到HA的效验)
2、kafka分派replica算法:
分配条件
N 个broker
x 个 partition
y 个replica
分配方式
将所有的broker和所有的partition进行排序
把第i个partition分配到 [i [ mod] n](i 除以 你的余数)(就是从第一台broker上开始部署,部署到最后一台broker,如果还没部署完,怎进行循环)个broker上(分配topic的分区的部署位置)
把第i个partition的第j个replica分配到[(i+j) mod n]个broker上,效果和上年的分配partition是一样的.
3、如何进行主从数据propagate
有一个前提,product生产的消息只是和partition的leader进行通信,是不关心partition是有多少个replica的.
product在发布消息到partition时,先通过zookeeper找到该partition的leader
leader把数据写入log
所有的follower都从leader pull拉去数据,而后写入这些follower的log里面
通过pull的方式可以保证replica的消息顺序是和其leader的消息顺序一致
然后每个follower都向leader发送ACK
一但leader收到ISR(同步列表)的所有ACK,则认为该条消息已经被commit了
**4、为了保住高吞吐量,kafka同样对replication的过程做了优化,
过程不是纯同步(性能会很忙),也不是纯异步(消息会丢失)**
kafka采用了ISR列表的方式来进行维护
ISR列表标识in-sync Replica 其意义为:与leader保持同步的Replica列表
如果一个Follower宕机,或者落后太多,Leader将把它从ISR中移除。
Kafka处理失败需要明确定义一个Broker是否“活着”。对于Kafka而言,Kafka存活包含两个条件,一是它必须维护与ZooKeeper session(这个通过ZooKeeper的Heartbeat机制来实现)。二是Follower必须能够及时将Leader的消息复制过来,不能“落后太多”。
二、如何保证给product ACK之前的备份数量
**1、需要说明的是,Kafka只解决fail/recover,不处理“Byzantine”(“拜占庭”)问题。**
**2、一条消息只有被ISR里的所有Follower都从Leader复制过去才会被认为已提交。**
**3、而对于Producer而言,它可以选择是否等待消息commit,这可以通过request.required.acks来设置。**
**4、这种机制确保了只要ISR有一个或以上的Follower,一条被commit的消息就不会丢失。**
三、如何进行Leader Election
1、使用的选举Leader方式
Kafka在ZooKeeper中动态维护了一个ISR(in-syncreplicas),这个ISR里的所有Replica都跟上了leader,只有ISR里的成员才有被选为Leader的可能。
在这种模式下,对于f+1个Replica,一个Partition能在保证不丢失已经commit的消息的前提下容忍f个Replica的失败。在大多数使用场景中,这种模式是非常有利的。
四、如何处理所有的replica都宕机了
1、等待ISR中的任一个Replica“活”过来,并且选它作为Leader
2、选择第一个“活”过来的Replica(不一定是ISR中的)作为Leader
五、如何选举leader
1、它在所有broker中选出一个controller,所有Partition的Leader选举都由controller决定。
**2、controller会将Leader的改变直接通过RPC的方式(比ZooKeeper Queue的方式更高效)通知需为为此作为响应的Broker。
3、同时controller也负责增删Topic以及Replica的重新分配。
**
六、节点故障企切换过程(broker failover)
**1. Controller在ZooKeeper注册Watch,一旦有Broker宕机(这是用宕机代表任何让系统认为其die的情景,包括但不限于机器断电,网络不可用,GC导致的Stop The World,进程crash等),其在ZooKeeper对应的znode会自动被删除,ZooKeeper会fire Controller注册的watch,Controller读取最新的幸存的Broker。
- Controller决定set_p,该集合包含了宕机的所有Broker上的所有Partition。**
3. 对set_p中的每一个Partition
3.1 从/brokers/topics/[topic]/partitions/[partition]/state读取该Partition当前的ISR
3.2
决定该Partition的新Leader。
如果当前ISR中有至少一个Replica还幸存,则选择其中一个作为新Leader,新的ISR则包含当前ISR中所有幸存的Replica。
否则选择该Partition中任意一个幸存的Replica作为新的Leader以及ISR(该场景下可能会有潜在的数据丢失)。
如果该Partition的所有Replica都宕机了,则将新的Leader设置为-1。
3.3 将新的Leader,ISR和新的leader_epoch及controller_epoch写入/brokers/topics/[topic]/partitions/[partition]/state。
注意,该操作只有其version在3.1至3.3的过程中无变化时才会执行,否则跳转到3.1
4. 直接通过RPC向set_p相关的Broker发送LeaderAndISRRequest命令。Controller可以在一个RPC操作中发送多个命令从而提高效率。