乐趣区

关于java:kafka同步数据机制

1、名词解释

1. 根本名词

  • 主题:topic。逻辑概念,用于辨别业务
  • 服务器:broker。接管长久化音讯,治理 topic,权限治理,consumer 重均衡等等
  • 分区:partition。一个有序的音讯序列,一个 topic 对应多个分区
  • 音讯:record。不做解释
  • 音讯位移:Offset。分区中每条音讯的地位
  • 生产者:producer。不做解释~~~~
  • 消费者:consumer。不做解释

2. 正本与 ISR

这两个是 broker 外面的两个概念名词。

所谓_正本 _,就是 kafka 为了进步可用性,将同一个 parition 数据扩散到不同 broker 的数据备份。 同时 kafka 会选出一个 leader 正本用于对外读,follower 则须要被动向 leader 正本申请同步 kafka 日志,以保障主从正本数据保持一致。

所谓_ISR_,就是有资格能被评比为 leader 正本的 follower 正本汇合。只有 leader 和 ISR 中所有正本都同步状态了,才会被 kafka 认为该音讯曾经提交。

3、正本中的概念

起始位移(base offset):该正本第一条音讯的位移

高水印值(high watermark, HW):该正本最新一条_曾经提交 _的音讯位移。_ 如果某个音讯的 offset 小于该值,则所有的正本都曾经同步这条音讯了;如果某个音讯的 offset 大于该值,则肯阐明些正本还没同步到这条音讯_。换一种说法,所有 offset 小于该值的音讯对 consumer 是可见的;而大于该值的是不可见的。该值十分重要,他的值影响到正本主从同步的地位,影响到 consumer 生产数据的地位。应该留神的是,HW 不止在 leader 里存在,在 follower 里也存在,其起因就是为了避免 leader 解体,follower 也能立刻顶替 leader 进行失常工作(最终一致性)。

日志末端位移(Clog end offset, LEO):该正本最初一条信息的位移

2、音讯同步流程

1、整体流程

①broker1 上的 leader 正本接管到音讯,把本人的 LEO 值更新为 1。

②broker2 和 broker3 上的 follower 正本各自发送申请给 broker 1。(个别状况下,是 follower 定时给 leader 发送 fetch 申请的,就如同 heartbeat 心跳)

③broker1 收到 fetch 申请后,被动别离把该音讯推送给 follower 正本。

④follower 正本接管到音讯后各自更新本人的 LEO 为 1,并返回 response。

⑤leader 正本接管到其余 follower 正本的数据申请响应(response)之后,更新 HW 值为 1。此时位移为 0 的这条音讯能够被 consumer 生产。

2、流程细节

_准则:HW 是以后已知的所有 LEO 的最小值_。为什么呢?失常状况下,各个 broker 的 partition 数据都是程序写入的,最小的 LEO 意味着所有的正本都同步到了这个 LEO 以前的所有数据,就满足了“HW 之前的音讯都曾经同步实现”的要求。

为了便于形容,咱们假如有两个正本在同步数据,一个 leader 一个 follower

  • 第一轮 fetch

在某一时刻,leader 收到了一条信息,写入了底层数据,接下来就是数据同步的过程了。

1、leader 的 LEO +1,好了解,有了一条信息,尾数须要加一。

2、leader 尝试更新 HW,取所有正本 LEO 最小值,本例是 0。那么,哪里获取各个正本最小值呢?leader 正本本地有个中央专门负责缓存这个数据,其余 follower 通过 fetch 申请告知 leader

这个时候,follower 发送了 fetch(fetch 申请里会带着本人当初的 LEO,当初是 0),leader 收到了 fetch

3、leader 收到了 fetch,尝试更新 HW。所有正本 LEO 最小值。本人的是 1,fetch 里是 0,那么是 0。

4、获取 offset >follower LEO 的数据放到 response 里,同时将本人的 HW(留神!!此时是全局 LEO 最小值)放到 response 里,本例里是 0

5、follower 承受到了 response,将数据写入,同时更新 LEO,本例里 +1

6、follower 尝试更新 HW,是全局 LEO 最小值,比拟 response 里的 HW 和本人的 LEO 取最小值即可(下面红字的个性,这里就用到了)。本例里更新后是 0

此时第一轮 fetch 完结,应该留神到,第一轮 fetch 实现后,数据尽管同步过来了,然而还不可见,因为 leader 此时还不晓得 follower 是不是同步胜利了

  • 第二轮 fetch

1、follower 发送了 fetch 申请,携带本人的 LEO=1

2、leader 尝试更新 HW,全局 LEO 的最小值,因而是 1

3、获取 offset >follower LEO 的数据放到 response 里,这次没有数据,同时将本人的 HW= 1 放到 response 里

4、follower 收到信息,没数据写入,而后尝试更新本人的 HW,全局最小值,本例 HW=1

此时第二轮 fetch 完结,此时此刻,数据同步才真正完结,这条新数据对外可见了

3、数据失落问题

综合下面的阐述,通过两轮 fetch 过程后才会对外可见。这个时间差就容易导致数据失落或者不统一的问题

场景一:两轮 fetch 两头产生 follwer 和 leader 先后解体,前提:leader 写入实现即认为已提交

如图,如果第二轮 fetch 产生,A 曾经更新了 HW,然而还没有包装 response 返回给 B,此时 B 产生了解体。重启后的 B 会将 LEO 调整成解体前的 HW 值,那么前面的数据就被删除了(看,此时呈现了一次数据不统一)。这个时候 B 想要向 A 发动 fetch,如果这个时候恰好 A 挂掉了,B 被选为 leader,A 重启回来后就会 fetch 取 leader 的 HW 和本人的 LEO 比拟取最小值,最初失去 HW=1,这样原来 HW= 2 的数据就永恒失落了。

场景二:两轮 fetch 中,follower 和 leader 同时解体

还是下面那种状况,第二轮 fetch 产生,A 曾经更新了 HW,然而还没有包装 response 返回给 B。这个时候 leader 和 follower 同时解体,而后 B 先重启成为 leader 了。这个时候,producer 发送了一个音讯记录到 B,此时因为没有 follower,因而间接更新 HW 到 2。而后 A 回来成为 follower,这时,A 发现自己的 HW 和 B 的 HW 相等,因而不做变更。然而 A 的 HW 指向的音讯和 B 的 HW 指向的音讯并不是一回事,这显然就不是咱们想要的了。

4、数据失落问题的解决

kafka 0.11 版本之后引入了 leader epoch(我了解其实就是带有版本信息的 HW)来取代 HW,同时重启后的 follower 减少了一种申请,解决了这个问题。(这也是为啥商业应用基本上都用 0.11 之后的版本)。epoch 实际上是一对值(epoch,offset)。epoch 示意 leader 的版本号,offset 示意本次写入的地位。比方(0,0)就代表这是第一次写入,写入地位是 0。(1,120)就代表,这是第二次写入,写入地位是 120(后面曾经写了 119 个数据)

场景一的解决:


场景二的解决:

** 附录:leader 中 HW 的更新条件 **

1.  正本成为 leader 正本的时候
2.  集群里有 broker 解体,退出 ISR 的时候
3.  producer 向 leader 推送数据的时候
退出移动版