KAFKA-16115: Adding missing heartbeat metrics - #15216
Conversation
c26fc90 to
0d6fcce
Compare
clean up remove bad code
e186171 to
6bd15e8
Compare
4e5db22 to
6759da1
Compare
bfc97f7 to
c55dae2
Compare
6fa1ff7 to
a8631cb
Compare
a8631cb to
6151964
Compare
clean up remove bad code
…kafka into ctr-heartbeat-metrics
867a10b to
6285909
Compare
| private long pollStartMs; | ||
| private long timeSinceLastPollMs; | ||
|
|
||
| public KafkaConsumerMetrics(Metrics metrics, String metricGrpPrefix) { |
There was a problem hiding this comment.
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() { |
|
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! |
|
Thanks, @philipnee. I will not get to it today, but I will review it tomorrow. |
lucasbru
left a comment
There was a problem hiding this comment.
@philipnee. Thanks for the PR, I left some comments
| * sending heartbeat until the next poll. | ||
| */ | ||
| private final Timer pollTimer; | ||
| private final HeartbeatMetricsManager metricsManager; |
There was a problem hiding this comment.
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; |
| Map<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>(); | ||
| offsets.put(new TopicPartition("t1", 0), new OffsetAndMetadata(0)); | ||
| commitRequestManger.addOffsetCommitRequest(offsets, Optional.empty(), false); | ||
| assertPoll(1, commitRequestManger); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
are you suggesting making this a utility class?
There was a problem hiding this comment.
See the latest commit - i removed this class to simplify the implementation a bit
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Okay, if we are not affected by this, not closing it is okay with me.
|
I have one last comment, otherwise the PR looks good to me. |
|
@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 and I wonder if this is why we should remove these sensors upon closing. |
lucasbru
left a comment
There was a problem hiding this comment.
LGTM, thanks @philipnee. Restarting CI to see if the build failures are transient.
|
Hello @philipnee @lucasbru Why you remove GroupState class in this commit? |
|
@nizhikov Sorry, during review I thought @philipnee removed a left-over class from an earlier PR also called |
|
@lucasbru No worries. I wanted to make it clear that class removed by mistake and didn't broke something. |
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>
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>
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>
Add a HeartbeatMetrics module to measure various metrics related to the heartbeat. Here is the highlight of the changes:
Non-related refactor:
Some follow ups: