文章目录

LEO更新机制follower副本LEO更新leader副本LEO更新

HW更新机制follower更新HWleader更新HW

使用HW衡量数据同步情况的缺陷

LEO更新机制

follower副本LEO更新

Kafka设计了两套follower副本LEO属性,一套LEO值保存在follower副本所在的broker缓存上; 另一套LEO值保存在leader副本所在broker的缓存上,所以leader副本所在主机的缓存上保存了该分区下所有follower副本的LEO属性值。Kafka需要利用前者帮助follower副本自身更新HW值 而同时还需要使用后者来确定leader副本的HW值。

follower副本端的follower副本LEO何时更新?

follower副本端的follower副本LEO值就是该副本对象底层日志的LEO值,每当写入一条消息,其 LEO值就会+1,在follower发送fetch请求后,leader将数据返回给follower,此时follower开始向底层log写数据,从而自动更新其LEO值。

leader副本端的follower副本LEO何时更新?

leader副本端的follower副本LEO的更新发生在leader处理follower fetch请求时,一旦leader 接收到fetch请求,它首先会从自己的log中读取相应的数据,但是在给follower返回数据之前它先去更新自身缓存中的follower的LEO。

leader副本LEO更新

leader自身的LEO何时更新?

leader写log时就会自动更新自己的LEO值。

HW更新机制

follower更新HW

follower更新HW发生在其更新LEO之后,一旦follower向log写完数据,它就会尝试更新HW值,比较当前LEO与fetch响应中的HW值,取两者中较小的值作为新的HW值。所以各follower的HW值还是取决于leader中的HW值。

我们需要更关心leader副本的HW值,它直接影响了分区数据对consumer的可见性。下面几种情况,leader会尝试 更新分区HW值,有可能因为不满足条件而不做任何更新。

副本称为leader副本时;broker出现崩溃导致副本被踢出ISR时,若有broker崩溃,则必须查看是否会波及此分区,因此检查分区HW值 是否需要更新时有必要的。Producer向leader副本写入消息时:因为写入消息会更新leader的LEO,故有必要再查看HW值是否也需要更新。leader处理follower fetch请求时:当leader处理follower的fetch请求时,首先会从底层的log读取数据, 之后再尝试更新分区HW值。

leader更新HW

leader如何更新HW

当尝试确定分区HW时,leader会从自身缓存中拿出满足条件的follower副本的LEO值,并选出最小的LEO值作为HW值。 满足条件指的是follower处于ISR中,并且落后leader LEO的时长不大于replica.lag.time.max.ms值。

使用HW衡量数据同步情况的缺陷

如果leader和follower之间更新HW过程中,发生broker崩溃或者重启,导致leader转移。则会出现 消息数据丢失或副本数据不一致问题。

根本原因在于HW值被用于衡量副本备份的成功与否,以及在出现崩溃时作为日志截断的依据,但是HW值的更新是异步延迟的, 特别是需要外的fetch请求处理流程才能更新,所以这中间发生的任何崩溃都可能导致HW值过期。

数据丢失

数据不一致

解决方案

引入leader epoch来取代HW值,leader端开辟一段内存区域专门保存leader的epoch信息。所谓epoch 实际上是一对值(epoch,offset),epoch标识leader的版本号,从0开始,当leader变更过一次时,epoch就会加1,而offset则对应于该epoch版本的leader写入第一条消息的位移。如(0,0)和(1,120)标识第一个leader从位移0开始写入消息,共写了120条,而第二个leader版本号是1,从位移120处开始写入消息。

每个leader 中会保存这样一个缓存,并定期写入一个检查点文件中,当leader写底层log时,它会尝试更新整个缓存,如果这个leader首次些消息,则会在缓存中增加一条目,否则不做更新,而每次副本重新称为leader时会检查这部分缓存,获取对应leader版本的位移,这就不会发生数据不一致和丢失的问题。

规避数据丢失问题

避免数据不一致问题

查看原文