Every write operation goes to all replicas, but only responses

from a majority quorum are necessary to commit the write.

每一次写操作都分发到所有副本,只有大部分节点应答才能提交写

缺点:随着副本数的增加,集群中需要ack的节点数量比较多(n/2-1)

存储元数据,数据量不是很大,使用ZooKeeper比较合适


The ISR scheme of Kafka requires all the members of the current ​​ISR​​ to respond

对于一次写的提交,要求当前ISR中的所有成员都ack, 才算提交写成功

ISR的大小是可配置的,和副本数量没有关系.比如11个副本可以配置ISR=3, 如果用quorum,则需要6个节点ack


场景1: 节点挂掉后重新和Leader同步数据


场景2: 普通节点和Leader节点都挂了,选举新的Leader


Partition

每条消息都有一个唯一的offset. 一个Topic分成多个Partition

每个Partition中消息offset都是一直增加, LEO表示最后一条消息的offset

可以认为一个Partition内的offset是全局有序的,一个Partition分成多个Segment, 每个Segment的offset也都是有序的

Segment与Segment之间的offset也是有序的, 所有这些Segment组成的一个Partition就是全局有序的


Replication

Leader宕机, 新的Leader一定是从先前Leader的ISR中选举出来的

ISR是所有副本的子集, 是那些能够及时地复制Leader日志的节点


每个Partition的Leader通过计算每个副本和它相比落后的数量来跟踪(更新)ISR列表

当生产者生产一条消息给Broker,写到Leader节点, 并且复制到Partition的所有副本

但只有全部复制到ISR列表中的每个节点(ISR节点必须都ack), 这条消息才算被提交

复制到一个不在ISR列表中的节点, 即使没有ack也没有关系(因为它本身就比较慢了)

如果一个节点落后太多, 就会从ISR中移除. 这样复制延迟取决于ISR中最慢的节点

所以如果ISR中最慢的节点还不争气,也会被剔除掉, 最终在ISR中的节点一般都很快

假设副本数=3, 有三个Broker, 已经有三条消息committed了, 初始时所有的副本(包括Leader)都在ISR中

并且replica.lag.max.messages=4, 只要follower落后于Leader不超过3条消息, 就不会从ISR中移除

replica.lag.time.max.ms=500, 只要follower每隔500ms(或者更快)向Leader获取消息(fetch request)

就不会被标记为DEAD, 也就不会从ISR中移除(如果没有落后太多,但是长时间没fetch,也会被移除的).


  • lag.max.messages: detect slow replicas
  • lag.time.max: detect halted or dead replicas


Producer向Leader发送了一条消息, Leader的LEO增加了一.

这个时候Broker3由于某种原因卡住了, 无法从Leader上及时获取这条消息

而Broker2则正常地从Leader上同步了这条消息到自己本地.

由于一条消息被成功地提交的必要条件是: 在ISR中的所有节点都复制了这条消息.

Broker3还在ISR中, 只要它没有复制这条消息, 那么这条消息就不会被committed.

由于现在Broker3才落后Leader一条消息 < replica.lag.max.messages=4

所以它并不会从ISR中移除, 所以只能静静地等Broker3…

要么再多落后几条消息, 从ISR中移除

要么赶快恢复过来, 然后从Leader复制消息, 及时赶上Leader,不要落后太多


假设Broker3在100ms后恢复过来, 然后从Leader同步这条稍微延迟的消息

现在两个follower都复制了消息3, 由于ISR的所有节点都复制了消息3,

现在Leader的committed(HW)可以向后移动到消息3了.


如果Producer发送一批4条消息 = lag.max.messages = 4

所有的follower都落后于leader太多了, 它们会从ISR中删除


由于所有的follower都是alive的, 它们会在下次fetch request时赶上Leader的LEO

即复制这批消息, 现在落后的消息已经被补上了, 于是就会被重新加入到ISR中,

于此同时由于follower都复制了这批消息, committed也增加到最新的便宜位置


这种大批量的生产消息, 造成follower不断地shuttle in and out of ISR (移除后又添加)

而且需要根据topic的期望流量猜测正确的值, 看起来并不是很好控制!

现在统一只使用一个配置: replica.lag.time.max.ms 来控制stuck和slow的replica.

不过它的含义变为: follower上的副本和Leader相比out-of-sync的时间


  • stuck replica含义仍然不变:如果没有及时发送fetch request, 会被认为Dead,并移除
  • slow replica: 副本从刚开始落后与Leader, 直到超过这个时间,说明它太慢了也会移除

这样即使有突增流量或一直都是大批消息, 除非副本一直落后与Leader太长的时间

否则如果副本只要在这个时间内能赶上Leader, 就不会出现删除后又添加到ISR的现象