消息丢失的案例:
Leader接收消息后,更新Leader的LEO,但是Remote-LEO和HW并没有更新。
如果生产者设置acks=1,则表示此消息已经发送成功。如果acks=-1,默认 min.insync.replics=1
,也表示消息已经发送成功:
Follower拉取消息,放到本地,此时,更新Follower的LEO为3:
假如,在Follower发起第二次请求的时候,Leader和Follower都宕机,则:
两者随后重启,由于副本重启后以HW作为标准对消息进行截断,则无论哪个先重启,都会对消息进行截断,也就是消息3被丢弃:
消息丢失。
消息保持一致性:
所谓的消息一致性,指的是对于已经同步的消息,Follower应该和Leader消息一样。但是下图的情况就是消息不一致的情况:
发生背景:
Leader接收到消息,更新本地LEO为3:
Follower拉取消息,放到本地,此时,更新Follower的LEO为3:
Follower发起第二次请求,此时,Leader更新Remote-LEO为3,更新HW为3:
Leader回复Follower的时候,Leader和Follower宕机:
假如Follower先重启回来,进行消息截断,变为新的Leader,原来的Leader稍后重启,由于HW是3,因此不进行消息的截断,直接到新Leader拉取偏移量为3的消息。新的Leader开始接收生产者的消息。
此时Follower的{2}消息和Follower的2消息不一样,消息不一致,但是Follower不会从偏移量2开始拉取消息,而是从3拉取消息。
通过在本地记录epoch信息用于截断消息,防止与Leader不一致。
每次发生Leader的变更,控制器要生成新的epoch的值,同时新的Leader记录该键值对:<epoch, beginOffset>
其中beginOffset表示当前Leader从哪条消息开始接管:
Leader | Follower |
---|---|
<0, 0> <1, 10> <2, 25> <3, 50> | <0, 0> |
如:
request({0, 12}):Follower请求纪元为0的时候的偏移量为12的消息。
response(<1, 10>):返回比0大的最小纪元数和纪元对应的offset,意思是follower的纪元0的11,10两条消息多余,删除。