为了保障Prosucer发送的消息能可靠的发送到指定的Topic,Topic的每一个Partition收到消息后,要向Producer发送ACK,若是Produser收到ACK,就会进行下一轮发送,不然重试。缓存
为了提升消息的可靠性,Kafka每一个Topic的partition都有N个副本(replica)。这N个副本中,其中一个replica是Leader,其余都是Follower。 Leader负责处理Partition的全部请求,Follower负责同步Leader的数据。 下图展现了Kafka集群中的4个Broker,Topic有3个Partition。异步
Partition何时才会发送ACK呢? 要确保所有的Follower与Leader同步完成以后,Leader才能发送ACK,这样才能保证Leader挂掉以后,在全部Follower中能选出新的Leader。 可是万一有一个Follower由于故障,迟迟不能和Leader同步,Leader就得等着它完成同步以后才能发送ACK,怎么决解呢? 这就引出了ISR(in-sync replica set)。 ISR在Leader中维护,也叫同步副本队列,就是leader 与leader保持同步的followers的集合。 当ISR中的Follower完成数据的同步以后,Leader就会给Producer发送ACK,若是Follower未在规定的时间同步数据,则将其踢出ISR。当Leader挂掉的时候,在ISR中选举出一个新的Leader。学习
在学习复制原理以前,先看两个概念:HW(HighWatermark)和LEO(LogEndOffset):ui
如图: 3d
Leader与Follower中,都会维护各自的HW,对于新消息的写入,Consumer并不能当即被消费,须要等待ISR中的Followers从Leader中复制完成。 下图说明了新消息写入Partition后的数据复制过程: blog
由图可知,Kafka的复制既不是同步也不是异步,其在可靠性和吞吐量上有很好的平衡。队列
当Producer向Leader发送数据的时候,能够经过Kafka提供的三种ACK应答机制,对数据的可靠性与延迟的要求作平衡。 经过配置request.required.acks实现。kafka
Producer不等待Broker的ACK,这能保证最低的延迟,可是当Broker故障时,数据可能丢失,便可靠性最低。 体现了At Most Once语义,最多一次,数据只会发送一次,不保证数据会丢失。同步
Producer等待Broker中partition的Leader落盘成功后返回ACK。若是在Follower同步结束以前Leader故障,数据会丢失。it
Producer等待Partition的Leader和Follower所有落盘成功后返回ACK。若是在数据同步完成后,发送ACK以前Leader故障,Producer会从新发送消息,形成数据重复。 这体现了At Least Once语义,至少一次,能够保证数据不会丢失,可是不保证数据重复。
At Least Once 幂等性 = Exactly Once。 Kafka中幂等性是经过Broker初始化时分配的PID来保证。发往同一Partition的消息会附带Sequence Number(SN),而Broker会对(PID,Partition,SN)作缓存,当相同主键的消息提交时,Broker只会持久化一条。 可是PID重启后就会变化,不一样的Partition也具备不一样的主键,因此幂等性没法保证跨分区会话的Exactly Once。
Follower故障后会被临时踢出ISR,当Follower恢复后,Follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向Leader同步。等该Follower的LEO大于等于该partition的HW,即Follower追上Leader以后,就会被从新加入ISR。
Leader发生故障,会从ISR中选举出一个新的Leader,其他的Follower会先将各自的log文件高于各自HW的部分截取掉,以后重新的Leader同步数据。
kafka会在Zookeeper中为每一个partition动态的维护着ISR,当Leader挂掉后,会从ISR中顺序选择一个Follower做为主。 若是碰巧ISR中Follower所有挂掉,那么有两种选择:
怎么选择就要在可用性与一致性之间作权衡了。