在上节中,我们讲述了ISR,如何判断段follower副本与leader副本同步以及相关概念(HW、LEO),那么今天这节我们来看一下follower副本与leader副本的详细同步过程,但是这节所讲的同步过程是有弊端的,在新的版本中kafka对副本同步进行了优化,消除了这种弊端。
follower副本同步的过程大致就是向leader发起获取数据请求,leader给出响应并返回数据,然后follower副本更新自己的HW和LEO值,并且follower的请求数据过程中,leader也会更新自己的HW和LE,在这里注意一下,leder副本除了维护自己的HW和LEO值以外,还维护了一份各个follower副本的LEO值,这里我们就暂时叫他RemoteLEO。
再总结一下,follower副本的同步过程无非就是从leader副本获取数据写入log,然后更新HW和LEO的值。
假设我们新的kafka集群刚刚建立,没有任何生产者,没有消息,follower此时向leader发起fetch数据的请求,leader发现没有数据会将该请求暂时存在purgatory(用于临时存放暂时无法被处理的请求,但是这些请求有超时设置,如果超时则强制完成)中。Leader和follower的初始状态如下:

此时,假设生产者向kafka某个topic的分区发送了一条消息,leader副本会将自己的LEO值+1,HW值不变,RemoteLEO值不变。状态图如下:

kafka在接受到生产者的消息后,主要经历下述过程(这里假设follower暂时无发出fetch数据的请求):
当写入消息后,假设follower发出了fetch数据请求,因为有新的数据产生,所以leader会将新的数据响应给follower,follower在接收到新的数据以后,会将数据写入底层日志并且更新自己的LEO。状态图如下:

follower从发起fetch数据请求,到响应完成,leader和follower主要会经历下述过程:
以上步骤,一次fetch数据请求已全部完成,leader的HW、LEO、RemoteLEO均没有做出更新,follower将数据写入了底层日志并且更新了LEO。那么关于HW的更新则需要伴随再一次的fetch数据请求更新才能成功。正是因为HW需要两次fetch请求才能更新,因此kafka利用水印进行follower同步会产生数据丢失、数据不一致的问题(这个下一节讲)。下面让我们看一下第二次fetch请求后的结果状态图。
在经历过第二次fetch数据请求后,leader中的RemoteLEO和HW会成功更新为1,follower中的HW也会更新为1。状态图如下:

follower第二次发起fetch数据请求,到响应完成,leader和follower经历的过程和第一次没什么区别,只是请求和响应中的数据发生了变化:
更新顺序:有数据写入底层日志LEO更新,其次会尝试更新RemoteLEO,再尝试更新HW