-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-13916; Fenced replicas should not be allowed to join the ISR in KRaft (KIP-841, Part 2) #12181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KAFKA-13916; Fenced replicas should not be allowed to join the ISR in KRaft (KIP-841, Part 2) #12181
Changes from 1 commit
b6cb295
e04cb33
7a6e3cd
384681a
4d0621f
c024f96
827512b
66a0df5
3b869aa
6addd52
2743a96
e567abe
ef38b4f
a717d4a
b15a6cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -143,7 +143,6 @@ sealed trait PartitionState { | |
| * the high watermark as well as determining which replicas are required for acks=all produce requests. | ||
| * | ||
| * Only applicable as of IBP 2.7-IV2, for older versions this will return the committed ISR | ||
| * | ||
| */ | ||
| def maximalIsr: Set[Int] | ||
|
|
||
|
|
@@ -159,7 +158,7 @@ sealed trait PartitionState { | |
| } | ||
|
|
||
| sealed trait PendingPartitionChange extends PartitionState { | ||
| def lastCommittedState: PartitionState | ||
| def lastCommittedState: CommittedPartitionState | ||
| def sentLeaderAndIsr: LeaderAndIsr | ||
|
|
||
| override val leaderRecoveryState: LeaderRecoveryState = LeaderRecoveryState.RECOVERED | ||
|
|
@@ -168,11 +167,11 @@ sealed trait PendingPartitionChange extends PartitionState { | |
| } | ||
|
|
||
| case class PendingExpandIsr( | ||
| isr: Set[Int], | ||
| newInSyncReplicaId: Int, | ||
| sentLeaderAndIsr: LeaderAndIsr, | ||
| lastCommittedState: PartitionState | ||
| lastCommittedState: CommittedPartitionState | ||
| ) extends PendingPartitionChange { | ||
| val isr = lastCommittedState.isr | ||
| val maximalIsr = isr + newInSyncReplicaId | ||
| val isInflight = true | ||
|
|
||
|
|
@@ -191,11 +190,11 @@ case class PendingExpandIsr( | |
| } | ||
|
|
||
| case class PendingShrinkIsr( | ||
| isr: Set[Int], | ||
| outOfSyncReplicaIds: Set[Int], | ||
| sentLeaderAndIsr: LeaderAndIsr, | ||
| lastCommittedState: PartitionState | ||
| lastCommittedState: CommittedPartitionState | ||
| ) extends PendingPartitionChange { | ||
| val isr = lastCommittedState.isr | ||
| val maximalIsr = isr | ||
| val isInflight = true | ||
|
|
||
|
|
@@ -869,7 +868,7 @@ class Partition(val topicPartition: TopicPartition, | |
| val current = partitionState | ||
| !current.isInflight && | ||
| !current.isr.contains(followerReplicaId) && | ||
| isBrokerIsrEligible(followerReplicaId) | ||
| isReplicaIsrEligible(followerReplicaId) | ||
| } | ||
|
|
||
| private def isFollowerInSync(followerReplica: Replica): Boolean = { | ||
|
|
@@ -879,10 +878,10 @@ class Partition(val topicPartition: TopicPartition, | |
| } | ||
| } | ||
|
|
||
| private def isBrokerIsrEligible(brokerId: Int): Boolean = { | ||
| private def isReplicaIsrEligible(followerReplicaId: Int): Boolean = { | ||
| // In KRaft mode, only replicas which are not fenced nor in controlled shutdown are | ||
| // allowed to join the ISR. This does not apply to ZK mode. | ||
| !metadataCache.isBrokerFenced(brokerId) && !metadataCache.isBrokerInControlledShutdown(brokerId) | ||
| !metadataCache.isBrokerFenced(followerReplicaId) && !metadataCache.isBrokerShuttingDown(followerReplicaId) | ||
| } | ||
|
|
||
| /* | ||
|
|
@@ -1534,10 +1533,12 @@ class Partition(val topicPartition: TopicPartition, | |
| partitionEpoch | ||
| ) | ||
| val updatedState = PendingExpandIsr( | ||
| partitionState.isr, | ||
| newInSyncReplicaId, | ||
| newLeaderAndIsr, | ||
| partitionState | ||
| // The current partition state must be of type CommittedPartitionState | ||
| // if we are here. CommittedPartitionState is the only one with `isInflight` | ||
| // equals to false. | ||
| partitionState.asInstanceOf[CommittedPartitionState] | ||
|
dajac marked this conversation as resolved.
Outdated
|
||
| ) | ||
| partitionState = updatedState | ||
| updatedState | ||
|
|
@@ -1556,10 +1557,12 @@ class Partition(val topicPartition: TopicPartition, | |
| partitionEpoch | ||
| ) | ||
| val updatedState = PendingShrinkIsr( | ||
| partitionState.isr, | ||
| outOfSyncReplicaIds, | ||
| newLeaderAndIsr, | ||
| partitionState | ||
| // The current partition state must be of type CommittedPartitionState | ||
| // if we are here. CommittedPartitionState is the only one with `isInflight` | ||
| // equals to false. | ||
| partitionState.asInstanceOf[CommittedPartitionState] | ||
| ) | ||
| partitionState = updatedState | ||
| updatedState | ||
|
|
@@ -1621,41 +1624,45 @@ class Partition(val topicPartition: TopicPartition, | |
| case Errors.OPERATION_NOT_ATTEMPTED => | ||
| // Since the operation was not attempted, it is safe to reset back to the committed state. | ||
| partitionState = proposedIsrState.lastCommittedState | ||
|
dajac marked this conversation as resolved.
Outdated
|
||
| debug(s"Failed to alter partition to $proposedIsrState since there is a pending AlterPartition still inflight. " + | ||
| info(s"Failed to alter partition to $proposedIsrState since there is a pending AlterPartition still inflight. " + | ||
| s"Partition state has been reset to the latest committed state $partitionState") | ||
| false | ||
| case Errors.INELIGIBLE_REPLICA => | ||
|
dajac marked this conversation as resolved.
Outdated
|
||
| // Since the operation was rejected, it is safe to reset back to the committed state. This | ||
| // assumes that the current state was still the correct expected state. | ||
| // This is only raised in KRaft mode. | ||
| partitionState = proposedIsrState.lastCommittedState | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In KRaft mode, could the state be updated via metadata and applied concurrently such that processing this would override a concurrently updated last state?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We rollback the previous partition state here only if the the partition state still matches our proposed partition state. If it does not, it means that the partition was updated via the metadata log in the mean time. This check is in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. This invariant isn't immediately visible from this code so maybe a comment and / or assert would make it more clear. |
||
| debug(s"Failed to alter partition to $proposedIsrState since the controller rejected at least one replica " + | ||
| info(s"Failed to alter partition to $proposedIsrState since the controller rejected at least one replica " + | ||
| s"because it is ineligible to join the ISR. Partition state has been reset to the latest committed state $partitionState.") | ||
| false | ||
| case Errors.UNKNOWN_TOPIC_OR_PARTITION => | ||
| debug(s"Failed to alter partition to $proposedIsrState since the controller doesn't know about " + | ||
| "this topic or partition. Giving up.") | ||
| "this topic or partition. Partition state may be out of thing, awaiting new the latest metadata.") | ||
|
dajac marked this conversation as resolved.
Outdated
|
||
| false | ||
| case Errors.UNKNOWN_TOPIC_ID => | ||
| debug(s"Failed to alter partition to $proposedIsrState since the controller doesn't know about " + | ||
| "this topic. Giving up.") | ||
| "this topic. Partition state may be out of thing, awaiting new the latest metadata.") | ||
| false | ||
| case Errors.FENCED_LEADER_EPOCH => | ||
| debug(s"Failed to alter partition to $proposedIsrState since the leader epoch is old. Giving up.") | ||
| debug(s"Failed to alter partition to $proposedIsrState since the leader epoch is old. " + | ||
| "Partition state may be out of thing, awaiting new the latest metadata.") | ||
| false | ||
| case Errors.INVALID_UPDATE_VERSION => | ||
| debug(s"Failed to alter partition to $proposedIsrState because the partition epoch is invalid. Giving up.") | ||
| debug(s"Failed to alter partition to $proposedIsrState because the partition epoch is invalid. " + | ||
| "Partition state may be out of thing, awaiting new the latest metadata.") | ||
| false | ||
| case Errors.INVALID_REQUEST => | ||
| debug(s"Failed to alter partition to $proposedIsrState because the request is invalid. Giving up.") | ||
| debug(s"Failed to alter partition to $proposedIsrState because the request is invalid. " + | ||
| "Partition state may be out of thing, awaiting new the latest metadata.") | ||
| false | ||
| case Errors.NEW_LEADER_ELECTED => | ||
| // The operation completed successfully but this replica got removed from the replica set by the controller | ||
| // while completing a ongoing reassignment. This replica is no longer the leader but it does not know it | ||
| // yet. It should remain in the current pending state until the metadata overrides it. | ||
| // This is only raised in KRaft mode. | ||
| debug("The alter partition request successfully updated the partition state but this replica got " + | ||
| "removed from the replica set while completing a reassignment. Waiting on new metadata to clean up this replica.") | ||
| debug(s"The alter partition request successfully updated the partition state to $proposedIsrState but " + | ||
| "this replica got removed from the replica set while completing a reassignment. " + | ||
| "Waiting on new metadata to clean up this replica.") | ||
| false | ||
| case _ => | ||
| warn(s"Failed to update ISR to $proposedIsrState due to unexpected $error. Retrying.") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.