-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-9724 Newer clients not always sending fetch request to older brokers #8376
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
Changes from all commits
c7ba8d5
4a461ec
349d7e4
8433abb
567dc2d
48605dc
ce38b74
45c20d8
c8d4a8c
7a1d6e6
e05d8ad
aa87a4b
37bb3a5
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 |
|---|---|---|
|
|
@@ -16,7 +16,9 @@ | |
| */ | ||
| package org.apache.kafka.clients.consumer.internals; | ||
|
|
||
| import org.apache.kafka.clients.ApiVersions; | ||
| import org.apache.kafka.clients.Metadata; | ||
| import org.apache.kafka.clients.NodeApiVersions; | ||
| import org.apache.kafka.clients.consumer.ConsumerRebalanceListener; | ||
| import org.apache.kafka.clients.consumer.NoOffsetForPartitionException; | ||
| import org.apache.kafka.clients.consumer.OffsetAndMetadata; | ||
|
|
@@ -45,6 +47,8 @@ | |
| import java.util.stream.Collector; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.apache.kafka.clients.consumer.internals.Fetcher.hasUsableOffsetForLeaderEpochVersion; | ||
|
|
||
| /** | ||
| * A class for tracking the topics, partitions, and offsets for the consumer. A partition | ||
| * is "assigned" either directly with {@link #assignFromUser(Set)} (manual assignment) | ||
|
|
@@ -422,8 +426,29 @@ public synchronized void position(TopicPartition tp, FetchPosition position) { | |
| assignedState(tp).position(position); | ||
| } | ||
|
|
||
| public synchronized boolean maybeValidatePositionForCurrentLeader(TopicPartition tp, Metadata.LeaderAndEpoch leaderAndEpoch) { | ||
| return assignedState(tp).maybeValidatePosition(leaderAndEpoch); | ||
| /** | ||
| * Enter the offset validation state if the leader for this partition is known to support a usable version of the | ||
| * OffsetsForLeaderEpoch API. If the leader node does not support the API, simply complete the offset validation. | ||
| * | ||
| * @param apiVersions | ||
| * @param tp | ||
| * @param leaderAndEpoch | ||
| * @return true if we enter the offset validation state | ||
| */ | ||
| public synchronized boolean maybeValidatePositionForCurrentLeader(ApiVersions apiVersions, TopicPartition tp, | ||
| Metadata.LeaderAndEpoch leaderAndEpoch) { | ||
| if (leaderAndEpoch.leader.isPresent()) { | ||
| NodeApiVersions nodeApiVersions = apiVersions.get(leaderAndEpoch.leader.get().idString()); | ||
| if (nodeApiVersions == null || hasUsableOffsetForLeaderEpochVersion(nodeApiVersions)) { | ||
| return assignedState(tp).maybeValidatePosition(leaderAndEpoch); | ||
| } else { | ||
| // If the broker does not support a newer version of OffsetsForLeaderEpoch, we skip validation | ||
| completeValidation(tp); | ||
| return false; | ||
| } | ||
| } else { | ||
| return assignedState(tp).maybeValidatePosition(leaderAndEpoch); | ||
|
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. I wonder, do we really need this call here? If the leader is not present the epoch shouldn't be present either -- right? If that's the case, then the call to maybeValidatePosition will short circuit private boolean maybeValidatePosition(Metadata.LeaderAndEpoch currentLeaderAndEpoch) {
if (this.fetchState.equals(FetchStates.AWAIT_RESET)) {
return false;
}
if (!currentLeaderAndEpoch.leader.isPresent() && !currentLeaderAndEpoch.epoch.isPresent()) {
return false;
}
if (position != null && !position.currentLeader.equals(currentLeaderAndEpoch)) {
FetchPosition newPosition = new FetchPosition(position.offset, position.offsetEpoch, currentLeaderAndEpoch);
validatePosition(newPosition);
preferredReadReplica = null;
}
return this.fetchState.equals(FetchStates.AWAIT_VALIDATION);
}
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. Oh, actually looking at the javadoc for LeaderAndEpoch, I see
Also in Metadata, we do return a LeaderAndEpoch with the last-seen epoch, but no leader if the metadata is stale. So, I guess it makes sense to keep this call in maybeValidatePositionForCurrentLeader |
||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this since at this point the two callers have different needs for updating the epoch and adding a flag felt pretty kludgy