Skip to content

KAFKA-15615: Improve handling of fetching during metadata updates #15647

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

Open
wants to merge 9 commits into
base: trunk
Choose a base branch
from

Conversation

appchemist
Copy link
Contributor

@appchemist appchemist commented Apr 2, 2024

Problem

As stated in the KAFKA-15615
When a fetch response receives an error about partition leadership, fencing, etc. a metadata refresh is triggered.
Until its metadata is updated, the consumer will continue to attempt fetching data for the partition, resulting in failure responses due to outdated information.

Approach

In cases where a partition requires metadata updates due to Fetch response, a temporary "Pause" approach is applied.

  • In this situation, the partition transitions to the AWAIT_UPDATE (ADD) state.
  • The AWAIT_UPDATE state is an Unfetchable state (TopicPartitionState.isFetchable() is false).
  • In other words, the partition is excluded from the Fetch targets in AbstractFetch.fetchablePartitions.
  • For KIP-951, if the fetch error response includes CurrentLeader information, the subscription remains fetchable as is.

AWAIT_UPDATE

  • Transitions from
    • FETCHING
  • Transitions to
    • FETCHING
    • AWAIT_RESET
    • AWAIT_VALIDATION
    • AWAIT_UPDATE
  • Even if the metadata is updated without changes to Leader and Epoch information in the AWAIT_UPDATE state, the. partition transitions to the next state by SubscriptionState.maybeValidatePositionForCurrentLeader.
    • FETCHING
    • AWAIT_VALIDATION
  • requiresPosition true
  • hasValidPosition false

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@appchemist appchemist changed the title KAFKA-15615: Improve handling of fetching during metadata updates KAFKA-15615: Improve handling of fetching during metadata updates. Apr 9, 2024
@johnnychhsu
Copy link
Contributor

thanks for the PR!
just curious, what is the problem without the newly added state? does it cause any issues?

@appchemist
Copy link
Contributor Author

thanks for the PR! just curious, what is the problem without the newly added state? does it cause any issues?

@johnnychhsu
When a kafka consumer encounters a FENCED_LEADER_EPOCH error or other errors requiring metadata updates, a metadata update is triggered.
However, subscription's fetchstate is FETCHING.
In this state, the consumer will continuously fetch from the old leader.(because of PreferredReadReplica is reset and metadata is not yet updated)

This patch is designed to make consumer wait without sending fetch while metadata is being updated.

@appchemist
Copy link
Contributor Author

@kirktrue, PTAL, thanks in advance.

@kirktrue
Copy link
Contributor

@appchemist—thanks for the PR, and sorry for the delay in response!

I've taken a first pass but am still working through the unit test changes.

@appchemist
Copy link
Contributor Author

@kirktrue Thanks for the heads-up!
If you have a moment, please take a look

Copy link
Contributor

@kirktrue kirktrue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, @appchemist!

Just a few comments/questions.

Comment on lines 330 to 346
error == Errors.REPLICA_NOT_AVAILABLE ||
error == Errors.FENCED_LEADER_EPOCH) {
log.debug("Error in fetch for partition {}: {}", tp, error.exceptionName());
requestMetadataUpdate(metadata, subscriptions, tp);
} else if (error == Errors.REPLICA_NOT_AVAILABLE ||
error == Errors.KAFKA_STORAGE_ERROR ||
error == Errors.FENCED_LEADER_EPOCH ||
error == Errors.OFFSET_NOT_AVAILABLE) {
log.debug("Error in fetch for partition {}: {}", tp, error.exceptionName());
requestMetadataUpdate(metadata, subscriptions, tp);
subscriptions.awaitUpdate(tp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, if the replica is not available, we will flag the partition as awaiting a metadata update. Is this a key part of this change? Why don't we want the first if block to also await an update?

Copy link
Contributor Author

@appchemist appchemist Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
I missed that.

For this case, there is no need to await a metadata update.
I think simply initializing the PreferredReadReplica should be enough.
Since FetchUtils.requestMetadataUpdate() is already being called, it should also be initializing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Comment on lines 203 to 205
} else {
requestMetadataUpdate(metadata, subscriptions, partition);
subscriptions.awaitUpdate(partition);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, we first request a metadata update, then flag our partition as awaiting the metadata update whenever we encounter a NOT_LEADER_OR_FOLLOWER or FENCED_LEADER_EPOCH. However, in the FetchCollector.handleInitializeErrors() method, we only only request the metadata update, but don't flag the partition. Is that seeming inconsistency intentional?

Copy link
Contributor Author

@appchemist appchemist Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the FetchStates is FETCHING as per KIP-951, the FetchCollector.handleInitializeErrors() method is called.
I thought that in this case, it should not be changed to AWAIT_UPDATE.
Additionally, if it's AWAIT_UPDATE, it will be filtered out by the following code inside the FetchCollector.initialize() method and will not go through FetchCollector.handleInitializeErrors().

if (!subscriptions.hasValidPosition(tp)) {
   // this can happen when a rebalance happened while fetch is still in-flight
   log.debug("Ignoring fetched records for partition {} since it no longer has valid position", tp);
   return null;
}

Copy link
Contributor Author

@appchemist appchemist Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As another alternative, it could change the status to AWAIT_UPDATE in FetchCollector.handleInitializeErrors() only when it doesn't include leader info
Upon further thought, it seems possible to differentiate based on the following conditions.

completedFetch.partitionData.currentLeader().leaderId() != -1 && completedFetch.partitionData.currentLeader().leaderEpoch() != -1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@appchemist
Copy link
Contributor Author

Thanks for review! @kirktrue

@appchemist appchemist changed the title KAFKA-15615: Improve handling of fetching during metadata updates. KAFKA-15615: Improve handling of fetching during metadata updates Apr 26, 2024
appchemist and others added 8 commits April 28, 2024 18:41
- AWAIT_UPDATE transitions to the next state if the Leader information in the updated metadata is the same as the existing one.
…als/SubscriptionState.java


LGTM

Co-authored-by: Kirk True <[email protected]>
- Just requestMetadataUpdate in REPLICA_NOT_AVAILABLE error
- Move await a metadata update logic from AbstractFetch to FetchCollector
- Add test cases about REPLICA_NOT_AVAILABLE error
- Fix some comments
@kirktrue
Copy link
Contributor

kirktrue commented May 2, 2024

@lianetm & @philipnee—would you be able to review this PR? Thanks!

@appchemist
Copy link
Contributor Author

@lianetm & @philipnee If you have a moment, please take a look

error == Errors.KAFKA_STORAGE_ERROR ||
error == Errors.FENCED_LEADER_EPOCH ||
if (error == Errors.REPLICA_NOT_AVAILABLE) {
log.debug("Received replica not available error in fetch for partition {}", tp);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirktrue It's just a debug log, but it's different from the previous log. Is that okay?

Comment on lines 203 to 205
} else {
requestMetadataUpdate(metadata, subscriptions, partition);
subscriptions.awaitUpdate(partition);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

Comment on lines 330 to 346
error == Errors.REPLICA_NOT_AVAILABLE ||
error == Errors.FENCED_LEADER_EPOCH) {
log.debug("Error in fetch for partition {}: {}", tp, error.exceptionName());
requestMetadataUpdate(metadata, subscriptions, tp);
} else if (error == Errors.REPLICA_NOT_AVAILABLE ||
error == Errors.KAFKA_STORAGE_ERROR ||
error == Errors.FENCED_LEADER_EPOCH ||
error == Errors.OFFSET_NOT_AVAILABLE) {
log.debug("Error in fetch for partition {}: {}", tp, error.exceptionName());
requestMetadataUpdate(metadata, subscriptions, tp);
subscriptions.awaitUpdate(tp);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@mjsax mjsax added consumer and removed consumer labels Jul 22, 2024
@philipnee philipnee added the KIP-848 The Next Generation of the Consumer Rebalance Protocol label Jul 23, 2024
@kirktrue kirktrue added the ctr Consumer Threading Refactor (KIP-848) label Aug 27, 2024
@kirktrue kirktrue removed the KIP-848 The Next Generation of the Consumer Rebalance Protocol label Dec 11, 2024
Copy link

This PR is being marked as stale since it has not had any activity in 90 days. If you
would like to keep this PR alive, please leave a comment asking for a review. If the PR has
merge conflicts, update it with the latest from the base branch.

If you are having difficulty finding a reviewer, please reach out on the [mailing list](https://kafka.apache.org/contact).

If this PR is no longer valid or desired, please feel free to close it. If no activity occurs in the next 30 days, it will be automatically closed.

@github-actions github-actions bot added the stale Stale PRs label Mar 11, 2025
@appchemist
Copy link
Contributor Author

Hi @kirktrue
Are there any areas that need more work?
I know it's been deferred to version 4.0 for now.

@github-actions github-actions bot removed the stale Stale PRs label Mar 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clients consumer ctr Consumer Threading Refactor (KIP-848)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants