kafka学习笔记(一)--脑裂
我知道你想裂,但你先别裂
脑裂
用集群部署的大多数的分布式系统无可避免会面临脑裂问题。简单来说,脑裂就是在同一时刻出现了两个“Leader(或叫Master)”。设想这样一个场景:某分布式系统的分别部署在A,B两机房,每个机房有若干个节点。在正常情况下,这个分布式系统通过一致性协议(如 Paxos 或 Raft)来选举出一个 Leader,所有的读写请求都会通过 Leader 进行处理,副本们同Leader保持一致,确保数据的一致性。
假设一天出现了某种故障,A 机房和 B 机房之间的通信中断,且Leader丢失。这时,A 机房和 B 机房的节点可能会各自进行Leader选举,导致出现两个 Leader。这就是脑裂现象。
此时,如果多个不同区域的客户端向系统发送请求,根据就近路由的原则,用户可能向A机房的 leader 发送写请求,也可能向 B 机房的 leader 发送写请求,那么这两个请求可能会导致系统状态不一致。
为了解决脑裂问题,分布式系统通常会采取以下策略:
引入协调服务:使用 zooKeeper 作为第三方协调服务来管理 Leader 选举和节点状态。
采用一致性算法:通过使用 Paxos、Raft 等一致性算法,系统可以在网络分区发生时,保证只有一个 Leader 被选举出来。这些算法通常要求选举过程中获得超过半数节点的支持,以确保 Leader 的唯一性。
降低系统可用性:根据 CAP (Consistency,Availability,Partition tolerance)定理,在保证分区容错性的前提下,分布式系统必须在一致性和可用性之间做出选择。为了避免脑裂问题,系统可以牺牲部分可用性,例如拒绝处理写请求。
使用租约机制:分布式系统中的 Leader 可以通过租约(Lease)机制来确保其地位。Leader 需要在租约期限内,定期向其他节点发送心跳消息。如果租约到期,Leader 未能及时更新租约,那么其他节点会发起新一轮的选举。这样,即使出现脑裂现象,只要租约期限设置得当,系统也能在一定程度上保持一致性。
Kafka如何防止脑裂-Leader Epoch
为了解决脑裂kafka从0.11.0.0开始引入Leader Epoch的概念。
epoch是一个递增的整数。每当一个当新的leader被选举出来时,epoch都会+1。kafka的所有副本都会维护一个leader-epoch-checkpoint的文件,当eppch发生更新时,kafka会将矢量<LeaderEpoch => StartOffset> 追加到这个文件中,其中StartOffset表示当前的epoch下写入第一条消息的偏移量。副本在同步数据时,会将自己最新的epoch值一同发送给leader。leader收到follower的请求后,会检查请求中的epoch值。如果请求中的epoch值与当前leader的epoch值一致,说明follower与leader之间的同步关系符合预期,leader会接受follower的请求,将自己的数据复制给follower。如果请求中的epoch值小于当前leader的epoch值,说明follower已经过时,leader会拒绝follower的请求,并更新follower的epoch值。
# 查看leader-epoch-checkpoint
# broker ip
tail -f /kafka-logs/your—topic-partition/leader-epoch-checkpoint
0
1
此外,在查看leader-epoch-checkpoint的时候可能会注意到replication-offset-checkpoint 文件。这个文件记录了follower副本已经成功同步的各个主题分区的Offset信息。当follower副本重新启动或发生故障恢复时,会根据这个文件从正确的位置继续同步数据。
leader-epoch-checkpoint和replication-offset-checkpoint文件在Kafka中分别负责管理leader副本和follower副本的状态信息。它们之间的关系在于它们共同参与了Kafka副本同步和故障恢复的过程,确保了Kafka集群在面临故障时能够正确地恢复状态,保证数据的一致性和可靠性。
epoch的局限性
Kafka利用epoch机制确保了在leader发生变更时,follower副本能够及时更新自己的状态,避免了脑裂问题。在leader切换的过程中,可能会出现数据不一致的情况,这种方法在某种程度上牺牲了一致性。
如何将不一致性带来的损失降到最低? 用ISR
ISR列表
ISR(In-Sync Replicas)列表包含了分区的leader副本和已经成功同步了leader副本数据的follower副本。当选举发生时,新的leader会从ISR列表中选举出来,这样可以确保新的Leader副本拥有最新的数据,从而保证数据的一致性。
当Leader接收到客户端的写入请求后,它会将数据写入本地日志,并将数据发送给所有的Follower副本。当follower副本成功写入数据后,它会向Leader发送ACK确认。当leader收到ISR列表中的所有follower副本的ack后,它会认为写入操作成功完成,并向客户端返回成功响应。
当某个副本无法及时同步leader的数据时,它会被从ISR列表中移除,以确保ISR列表中的副本始终具有最新的数据。当该副本恢复正常并成功同步了Leader的数据后,再将它重新加入到ISR列表中。