Skip to content

KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric more efficient#8724

Merged
hachikuji merged 5 commits into
apache:trunkfrom
dajac:KAFKA-10040
Jun 5, 2020
Merged

KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric more efficient#8724
hachikuji merged 5 commits into
apache:trunkfrom
dajac:KAFKA-10040

Conversation

@dajac

@dajac dajac commented May 25, 2020

Copy link
Copy Markdown
Member

This PR changes the way PreferredReplicaImbalanceCount is computed. It moves from re-computing after the processing of each event in the controller to continuously maintaining the count.

Committer Checklist (excluded from commit message)

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

@hachikuji

Copy link
Copy Markdown
Contributor

ok to test

@ijuma
ijuma requested a review from junrao May 28, 2020 04:04
private def updatePreferredReplicaImbalanceMetric(partition: TopicPartition,
oldReplicaAssignment: Option[ReplicaAssignment],
oldLeadershipInfo: Option[LeaderIsrAndControllerEpoch],
newReplicaAssignment: Option[ReplicaAssignment],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: I think this exact argument doesn't need to be an Option

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.

Actually, in updatePartitionFullReplicaAssignment, partitionLeadershipInfo.get(topicPartition) returns an Option so it is more convenient to keep it as an Option. Ok for you?

}
}

private def isReplicaImbalance(replicaAssignment: ReplicaAssignment,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about hasPreferredLeader?

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, that is fine.

leadershipInfo: LeaderIsrAndControllerEpoch): Boolean = {
val preferredReplica = replicaAssignment.replicas.head
if (replicaAssignment.isBeingReassigned && replicaAssignment.addingReplicas.contains(preferredReplica))
// reassigning partitions are not counted as imbalanced until the new replica joins the ISR (completes reassignment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not something to change here, but it's a little curious that we only do this when a reassignment is in progress. I'm not sure it's useful to distinguish that case as opposed to a broker that is catching up after a restart. If the preferred leader is not in the ISR, then we can't elect it anyway. Seems like it might be more useful if this metric captured the "eligible imbalance".

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.

I agree with you.

partitionsForTopic(topic).filter { partition => states.contains(partitionState(partition)) }.toSet
}

def putLeadershipInfo(partition: TopicPartition, leaderIsrAndControllerEpoch: LeaderIsrAndControllerEpoch): Unit = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Wonder if we should consider making partitionLeadershipInfo private so that we do not mistakenly invoke put in the future directly.

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.

That makes total sense. I have updated the PR to make it private. I have added methods in the controller context for all the reads (moved code around).

if (!isActive) {
0
} else {
controllerContext.allPartitions.count { topicPartition =>

@hachikuji hachikuji Jun 3, 2020

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ouch. So the main issue is that we were doing this full iteration over all partitions on every controller event.

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.

Yeah...

@dajac

dajac commented Jun 3, 2020

Copy link
Copy Markdown
Member Author

@hachikuji @stanislavkozlovski I have addressed your comments. Could you have a second look?

@hachikuji

Copy link
Copy Markdown
Contributor

ok to test

@hachikuji

Copy link
Copy Markdown
Contributor

retest this please

1 similar comment
@hachikuji

Copy link
Copy Markdown
Contributor

retest this please

@hachikuji hachikuji left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the updates. Just a couple small comments.

}.keySet
}

def partitionLeadsOnBroker(brokerId: Int): Set[TopicPartition] = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: partitionLeadersOnBroker?

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.

That makes sense.

}

def partitionsWithLeaders(): Set[TopicPartition] = {
partitionLeadershipInfo.keySet

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This definition seems inconsistent with partitionsWithoutLeaders. I think you're just trying to preserve the existing logic. It might make sense to use a different name to avoid the apparent inconsistency? Maybe we could change partitionsWithoutLeaders to be partitionsWithOfflineLeaders or something like that. Looking at the caller, it looks like it would be reasonable to exclude topics which are being queued for deletion in both cases, but we could change that separately if you think it is risky.

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.

Right. I did not pay attention to this detail but that makes total sense to use a better name here. Let's go with partitionsWithOfflineLeaders.
We can indeed exclude topics which are being queued for deletion. It is already done in partitionsWithOfflineLeaders but I have added it in partitionsWithLeaders.

@dajac

dajac commented Jun 4, 2020

Copy link
Copy Markdown
Member Author

@hachikuji Thanks for the review. I have updated the PR based on your feedback.

@hachikuji

Copy link
Copy Markdown
Contributor

ok to test

@hachikuji hachikuji left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@hachikuji

Copy link
Copy Markdown
Contributor

retest this please

@hachikuji

Copy link
Copy Markdown
Contributor

I will go ahead and merge this. I build locally with JDK11 and Scala 2.13.

@hachikuji
hachikuji merged commit 7867c24 into apache:trunk Jun 5, 2020
@dajac
dajac deleted the KAFKA-10040 branch June 5, 2020 05:32
Kvicii pushed a commit to Kvicii/kafka that referenced this pull request Jun 6, 2020
* 'trunk' of github.com:apache/kafka: (46 commits)
  MINOR: improve code encapsulation between StreamThread and TaskManager (apache#8819)
  Fixing KAFKA-10094 (apache#8797)
  KAFKA-9851: Revoking Connect tasks due to connectivity issues should also clear the running assignment (apache#8804)
  KAFKA-9840; Skip End Offset validation when the leader epoch is not reliable (apache#8486)
  HOT_FIX: Update javadoc since imports added (apache#8817)
  KAFKA-8011: Fix flaky RegexSourceIntegrationTest (apache#8799)
  KAFKA-9570: Define SSL configs in all worker config classes, not just distributed (apache#8135)
  KAFKA-10111: Make SinkTaskContext.errantRecordReporter() a default method (apache#8814)
  KAFKA-10110: Corrected potential NPE when null label value added to KafkaMetricsContext (apache#8811)
  MINOR: Change the order that Connect calls `config()` and `validate()` to avoid validating if the required ConfigDef is null (apache#8810)
  MINOR: fix backwards incompatibility in JmxReporter introduced by KIP-606
  MINOR: Fix javadoc warnings (apache#8809)
  KAFKA-9441: Improve Kafka Streams task management (apache#8776)
  fix the broken links of streams javadoc (apache#8789)
  KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric more efficient (apache#8724)
  KAFKA-10066: TestOutputTopic should pass record headers into deserializers (apache#8759)
  MINOR: Add explanation for disabling forwarding from value transformers (apache#8771)
  KAFKA-10033: Throw UnknownTopicOrPartitionException if altering configs of non-existing topic
  KAFKA-9434: automated protocol for alterReplicaLogDirs (apache#8311)
  KAFKA-9313: Set `use_all_dns_ips` as the new default for `client.dns.lookup` (KIP-602) (apache#8644)
  ...
ijuma added a commit to confluentinc/kafka that referenced this pull request Jun 8, 2020
Conflicts:
* build.gradle: take upstream changes regarding heap memory
configuration for the build.

* apache-github/trunk: (33 commits)
  MINOR: fix HTML markup (apache#8823)
  KAFKA-10012; Reduce overhead of strings in SelectorMetrics (apache#8684)
KAFKA-9216: Enforce internal config topic settings for Connect workers
during startup (apache#8270)
  KAFKA-10097: Internalize checkpoint data (apache#8820)
KAFKA-10033: Throw UnknownTopicOrPartitionException when modifying a
non-existent topic's config
MINOR: improve code encapsulation between StreamThread and TaskManager
(apache#8819)
  Fixing KAFKA-10094 (apache#8797)
KAFKA-9851: Revoking Connect tasks due to connectivity issues should
also clear the running assignment (apache#8804)
KAFKA-9840; Skip End Offset validation when the leader epoch is not
reliable (apache#8486)
  HOT_FIX: Update javadoc since imports added (apache#8817)
  KAFKA-8011: Fix flaky RegexSourceIntegrationTest (apache#8799)
KAFKA-9570: Define SSL configs in all worker config classes, not just
distributed (apache#8135)
KAFKA-10111: Make SinkTaskContext.errantRecordReporter() a default
method (apache#8814)
KAFKA-10110: Corrected potential NPE when null label value added to
KafkaMetricsContext (apache#8811)
MINOR: Change the order that Connect calls `config()` and `validate()`
to avoid validating if the required ConfigDef is null (apache#8810)
MINOR: fix backwards incompatibility in JmxReporter introduced by
KIP-606
  MINOR: Fix javadoc warnings (apache#8809)
  KAFKA-9441: Improve Kafka Streams task management (apache#8776)
  fix the broken links of streams javadoc (apache#8789)
KAFKA-10040; Make computing the PreferredReplicaImbalanceCount metric
more efficient (apache#8724)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants