Skip to content

KAFKA-16115: Adding missing heartbeat metrics - #15216

Merged
lucasbru merged 30 commits into
apache:trunkfrom
philipnee:ctr-heartbeat-metrics
Feb 2, 2024
Merged

KAFKA-16115: Adding missing heartbeat metrics#15216
lucasbru merged 30 commits into
apache:trunkfrom
philipnee:ctr-heartbeat-metrics

Conversation

@philipnee

@philipnee philipnee commented Jan 17, 2024

Copy link
Copy Markdown
Contributor

Add a HeartbeatMetrics module to measure various metrics related to the heartbeat. Here is the highlight of the changes:

  • HeartMetrics encapsulate a heartbeat sensor
  • Add metrics suffix types to the AbstractConsumerMetrics so that it can be extended to different metric groups

Non-related refactor:

  • Rename the metric classes to "MetricManager" the reason being "Metrics" seems to relate to the Metric class however these managers are merely containers holding sensor references for recording purposes.
  • Created OffsetCommitMetricsManager so that we are more consistent with the metrics management
  • Extended KafkaConsumerMetrics to the AbstractConsumerMetrics so that the groupName is consistently created (without random concatenation)

Some follow ups:

  • Refactor commit sensor by introducing a CommitMetrics module so that we can keep most of the metrics in one place and let it be a bit more consistent stylistically
  • Possibly refactor fetch manager metrics

@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from c26fc90 to 0d6fcce Compare January 19, 2024 18:12
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from e186171 to 6bd15e8 Compare January 25, 2024 22:17
clean up test
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from 4e5db22 to 6759da1 Compare January 26, 2024 19:47
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from bfc97f7 to c55dae2 Compare January 26, 2024 23:35
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch 2 times, most recently from 6fa1ff7 to a8631cb Compare January 29, 2024 00:28
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from a8631cb to 6151964 Compare January 29, 2024 00:55
@philipnee
philipnee force-pushed the ctr-heartbeat-metrics branch from 867a10b to 6285909 Compare January 29, 2024 05:19
private long pollStartMs;
private long timeSinceLastPollMs;

public KafkaConsumerMetrics(Metrics metrics, String metricGrpPrefix) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i'm not even sure why we have metricGrpPrefix from the beginning - it is not specified by the user and it seems to always be the default.

return new ConsumerConfig(prop);
}

private HeartbeatRequestManager createHeartbeatRequestManager() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

dead code

@philipnee
philipnee marked this pull request as ready for review January 29, 2024 19:02
@philipnee

Copy link
Copy Markdown
Contributor Author

Hi @lucasbru - This PR is ready for review. I did a bit of refactor in this PR so not everything here is in the scope. Let me know what do you think!

@philipnee
philipnee requested a review from lucasbru January 29, 2024 23:47
@lucasbru

Copy link
Copy Markdown
Member

Thanks, @philipnee. I will not get to it today, but I will review it tomorrow.

@lucasbru lucasbru 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.

@philipnee. Thanks for the PR, I left some comments

* sending heartbeat until the next poll.
*/
private final Timer pollTimer;
private final HeartbeatMetricsManager metricsManager;

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'd either group this with the field below or separate this from pollTimer with a newline. Looks like the javadoc is referring to both fields like this.

final PendingRequests pendingRequests;
private boolean closing = false;
private Sensor commitSensor;
private OffsetCommitMetricsManager metricsManager;

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.

final?

Map<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>();
offsets.put(new TopicPartition("t1", 0), new OffsetAndMetadata(0));
commitRequestManger.addOffsetCommitRequest(offsets, Optional.empty(), false);
assertPoll(1, commitRequestManger);

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.

Did you remove this on purpose?

assertHeartbeat(heartbeatRequestManager, DEFAULT_HEARTBEAT_INTERVAL_MS);
assertEquals(0.06d, (double) getMetric("heartbeat-rate").metricValue(), 0.005d);
assertEquals(2.0, getMetric("heartbeat-total").metricValue());
time.sleep(DEFAULT_HEARTBEAT_INTERVAL_MS);

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.

I think here we can test some other value, since we don't really need this to be the heartbeat interval, right?


// test poll
assertHeartbeat(heartbeatRequestManager, 0);
time.sleep(DEFAULT_HEARTBEAT_INTERVAL_MS);

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.

The mixed use of DEFAULT_HEARTBEAT_INTERVAL_MS and heartbeatIntervalMs is confusing. Can use heartbeatIntervalMs consistently (if we need the extra alias) or just remove the alias and always use DEFAULT_HEARTBEAT_INTERVAL_MS ?

heartbeatRequestState,
backgroundEventHandler);
private KafkaMetric getMetric(final String name) {
return metrics.metrics().get(metrics.metricName(name, metricGroupPrefix + COORDINATOR_METRICS_SUFFIX));

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.

I'd suggest using the full metric name (including literal suffix) in these tests, like they appear in the documentation, and not reuse the constants from the prod code (otherwise we won't catch if those constants get modified incorrectly).

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class ConsumerMetricsManagerTest {

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.

If you think it's worth it splitting each group of metrics in a separate class, I would also split the corresponding unit tests into separate classes in the same metrics package, instead of having a combined unit test for all classes.

* </ul>
* </p>
*/
public abstract class AbstractConsumerMetricsManager {

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.

You don't have to change this, but personally, I don't think we need subclassing here. It seems all we get from it is a bunch of utilities, that could just be imported. Subclassing should be avoided if not necessary, and it creates complications (see, e.g. the current build failure).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

are you suggesting making this a utility class?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

See the latest commit - i removed this class to simplify the implementation a bit

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.

As I said, you didn't have to change this, but yes, I felt that the class was adding complexity of inheritance with little benefits.

import static org.apache.kafka.clients.consumer.internals.ConsumerUtils.CONSUMER_METRIC_GROUP_PREFIX;
import static org.apache.kafka.clients.consumer.internals.ConsumerUtils.COORDINATOR_METRICS_SUFFIX;

public class HeartbeatMetricsManager {

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.

I was checking why the CI was misbehaving... it's probably not related to the PR, but while I was checking it, I noticed that other metrics containers like KafkaConsumerMetrics are AutoClosable and are explicitly closed inside LegacyKafkaConsumer and AsyncKafkaConsumer, removing all sensors from the Metrics class. Now, I'm not sure if this would cause any leaks, but it seems it would at least be good style to close metrics managers in the same way. What do you think? Sorry, didn't notice this on the first pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought about this during the implementation. However, the current RequestManager is not "closeable" nor do we try to close anything during shutdown. I assume these sensors and metric map will be GC'ed upon program termination/fatal failure, so it occur to be a strange thing to do to remove these sensors from the map before closing.

If we need to - we should make RequestManager closeable as well as the metrics, so that we can close these resources upon program termination.

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.

GC should work fine with cyclic references. I suspect the point is that I can close my consumer, and I don't have to wait for GC to have the metrics cleaned up. You might even want to keep a reference to the consumer after it's closed, then GC will not kick in.

I'm not entirely sure if this is just a "nice-to-have" or if there is a strong reason to do this, but since adding a couple of close methods should be a quick thing, I would vote for cleaning the sensors up explicitly.

@philipnee philipnee Feb 1, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hey @lucasbru - The real issue is here: #7839

The PR claims it is only affecting KafkaConsumerMetrics: Both KafkaConsumerMetrics and SelectorMetrics are internally using the same mbean.

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.

Okay, if we are not affected by this, not closing it is okay with me.

@lucasbru

lucasbru commented Feb 1, 2024

Copy link
Copy Markdown
Member

I have one last comment, otherwise the PR looks good to me.

@philipnee

Copy link
Copy Markdown
Contributor Author

@lucasbru - Thank you for spending time reviewing the PR. I responded to your comment about resource closing. It is indeed a bit strange why we need to do this.

A weird thing I found while reviewing sensor code is that - there's a cyclic relationship between sensor and metrics. Sensor holds on to Metric's reference and Metrics holds on to sensor lookup map (which has Sensor as the val). See this

public class Metrics implements Closeable {

    private final MetricConfig config;
    private final ConcurrentMap<MetricName, KafkaMetric> metrics;
    private final ConcurrentMap<String, Sensor> sensors;

and

public final class Sensor {

    private final Metrics registry;

I wonder if this is why we should remove these sensors upon closing.

@lucasbru lucasbru 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, thanks @philipnee. Restarting CI to see if the build failures are transient.

@lucasbru
lucasbru merged commit f0087ac into apache:trunk Feb 2, 2024
@nizhikov

Copy link
Copy Markdown
Contributor

Hello @philipnee @lucasbru

Why you remove GroupState class in this commit?
This class will be used in java version of ConsoleGroupCommand when #14471 will be fully merged
Class was merged to trunk in ff25c35 to simplify further reviews.

@lucasbru

Copy link
Copy Markdown
Member

@nizhikov Sorry, during review I thought @philipnee removed a left-over class from an earlier PR also called GroupState. https://github.com/apache/kafka/blob/6e164bb9ace3ea7a1a9542904d1a01c9fd3a1b48/clients/src/main/java/org/apache/kafka/clients/consumer/internals/GroupState.java but instead he deleted a different class. I should have checked. Please, bring the class back and sorry for the confusion.

@nizhikov

Copy link
Copy Markdown
Contributor

@lucasbru No worries. I wanted to make it clear that class removed by mistake and didn't broke something.
Will return it in the next PR regarding Console Group Command.

yyu1993 pushed a commit to yyu1993/kafka that referenced this pull request Feb 15, 2024
Add a HeartbeatMetrics module to measure various metrics related to the heartbeat. Here is the highlight of the changes:

HeartMetrics encapsulate a heartbeat sensor
Add metrics suffix types to the AbstractConsumerMetrics so that it can be extended to different metric groups
Non-related refactor:

Rename the metric classes to "MetricManager" the reason being "Metrics" seems to relate to the Metric class however these managers are merely containers holding sensor references for recording purposes.
Created OffsetCommitMetricsManager so that we are more consistent with the metrics management
Extended KafkaConsumerMetrics to the AbstractConsumerMetrics so that the groupName is consistently created (without random concatenation)
Some follow ups:

Refactor commit sensor by introducing a CommitMetrics module so that we can keep most of the metrics in one place and let it be a bit more consistent stylistically
Possibly refactor fetch manager metrics

Reviewers: Lucas Brutschy <lbrutschy@confluent.io>
clolov pushed a commit to clolov/kafka that referenced this pull request Apr 5, 2024
Add a HeartbeatMetrics module to measure various metrics related to the heartbeat. Here is the highlight of the changes:

HeartMetrics encapsulate a heartbeat sensor
Add metrics suffix types to the AbstractConsumerMetrics so that it can be extended to different metric groups
Non-related refactor:

Rename the metric classes to "MetricManager" the reason being "Metrics" seems to relate to the Metric class however these managers are merely containers holding sensor references for recording purposes.
Created OffsetCommitMetricsManager so that we are more consistent with the metrics management
Extended KafkaConsumerMetrics to the AbstractConsumerMetrics so that the groupName is consistently created (without random concatenation)
Some follow ups:

Refactor commit sensor by introducing a CommitMetrics module so that we can keep most of the metrics in one place and let it be a bit more consistent stylistically
Possibly refactor fetch manager metrics

Reviewers: Lucas Brutschy <lbrutschy@confluent.io>
Phuc-Hong-Tran pushed a commit to Phuc-Hong-Tran/kafka that referenced this pull request Jun 6, 2024
Add a HeartbeatMetrics module to measure various metrics related to the heartbeat. Here is the highlight of the changes:

HeartMetrics encapsulate a heartbeat sensor
Add metrics suffix types to the AbstractConsumerMetrics so that it can be extended to different metric groups
Non-related refactor:

Rename the metric classes to "MetricManager" the reason being "Metrics" seems to relate to the Metric class however these managers are merely containers holding sensor references for recording purposes.
Created OffsetCommitMetricsManager so that we are more consistent with the metrics management
Extended KafkaConsumerMetrics to the AbstractConsumerMetrics so that the groupName is consistently created (without random concatenation)
Some follow ups:

Refactor commit sensor by introducing a CommitMetrics module so that we can keep most of the metrics in one place and let it be a bit more consistent stylistically
Possibly refactor fetch manager metrics

Reviewers: Lucas Brutschy <lbrutschy@confluent.io>
@lucasbru lucasbru added the ctr Consumer Threading Refactor (KIP-848) label Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ctr Consumer Threading Refactor (KIP-848)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants