Skip to content

KAFKA-20778: Avoid unneeded rebalance on classic consumer when replica unavailable#22768

Merged
lianetm merged 5 commits into
apache:trunkfrom
lianetm:lm-classic-rebalance-fix
Jul 8, 2026
Merged

KAFKA-20778: Avoid unneeded rebalance on classic consumer when replica unavailable#22768
lianetm merged 5 commits into
apache:trunkfrom
lianetm:lm-classic-rebalance-fix

Conversation

@lianetm

@lianetm lianetm commented Jul 6, 2026

Copy link
Copy Markdown
Member

Improve to avoid unnecessary double rebalance on the classic consumer
when a replica is bounced.

Before this PR, when a replica is bounced it resolves to an empty node
(no host) with a null rack on the consumer metadta view. The consumer's
metadata comparison treated that as a rack change (rack1 to null) and
triggered a rebalance, then a second one when the broker came back (null
to rack1). This affects the classic consumer, every assignor, when
client.rack is configured.

This PR improves the rack comparison to track racks by replica id and
treat an unavailable replica (empty node) as having an unknown rack
rather than a changed one: two metadata snapshots are equivalent if they
expose the same set of racks for available replicas, tolerating a
missing/unknown rack only when the replica it belongs to is unavailable.

Reviewers: David Jacot david.jacot@gmail.com

* a rack that is actually added or removed still is.
*/
boolean equivalentTo(PartitionRackInfo other) {
return racksAccountedForIn(other) && other.racksAccountedForIn(this);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we really need to check both ways here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the first one is for catching if a rack was removed (not related to an unvailable replica), needs rebalance, but does not catch if one was added (needs rebalance too), that's why checking both ways. Makes sense?

// Ids of the replicas whose broker is not in the current live-broker list (they resolve
// to an empty node), so their rack is unknown. Tracked by id so that a broker that is
// temporarily unavailable is not mistaken for a rack change.
private final Set<Integer> unknownReplicas;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: I wonder whether online and offline would be a better terminology. Not sure...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes, I think it's better too, done

// (replica 1 remains in the partition replicas, with an unknown rack) and then comes
// back on the same replica. Neither transition is a rack change, so no rebalance is
// expected at any point.
List<String> racks = Arrays.asList("rack-a", "rack-b", "rack-c");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Should we use List.of and Map.of where possible?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yup, done

@lianetm

lianetm commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Thanks @dajac ! Comments addressed

@dajac dajac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@lianetm lianetm merged commit 673107f into apache:trunk Jul 8, 2026
35 of 37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants