-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-7660: fix parentSensors memory leak #5953
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ | |
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.kafka.streams.processor.internals; | ||
| package org.apache.kafka.streams.processor.internals.metrics; | ||
|
|
||
|
|
||
| import org.apache.kafka.common.MetricName; | ||
|
|
@@ -23,12 +23,21 @@ | |
| import org.apache.kafka.common.metrics.Metrics; | ||
| import org.apache.kafka.common.metrics.Sensor; | ||
| import org.apache.kafka.common.utils.MockTime; | ||
| import org.apache.kafka.streams.processor.internals.metrics.StreamsMetricsImpl; | ||
| import org.junit.Test; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import static org.apache.kafka.common.utils.Utils.mkEntry; | ||
| import static org.apache.kafka.common.utils.Utils.mkMap; | ||
| import static org.apache.kafka.streams.processor.internals.metrics.StreamsMetricsImpl.PROCESSOR_NODE_METRICS_GROUP; | ||
| import static org.apache.kafka.streams.processor.internals.metrics.StreamsMetricsImpl.addAvgMaxLatency; | ||
| import static org.apache.kafka.streams.processor.internals.metrics.StreamsMetricsImpl.addInvocationRateAndCount; | ||
| import static org.hamcrest.Matchers.equalTo; | ||
| import static org.hamcrest.Matchers.greaterThan; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertThat; | ||
|
|
||
| public class StreamsMetricsImplTest { | ||
|
|
||
|
|
@@ -62,6 +71,60 @@ public void testRemoveSensor() { | |
|
|
||
| final Sensor sensor3 = streamsMetrics.addThroughputSensor(scope, entity, operation, Sensor.RecordingLevel.DEBUG); | ||
| streamsMetrics.removeSensor(sensor3); | ||
|
|
||
| assertEquals(Collections.emptyMap(), streamsMetrics.parentSensors()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testMutiLevelSensorRemoval() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: |
||
| final Metrics registry = new Metrics(); | ||
| final StreamsMetricsImpl metrics = new StreamsMetricsImpl(registry, ""); | ||
| for (final MetricName defaultMetric : registry.metrics().keySet()) { | ||
| registry.removeMetric(defaultMetric); | ||
| } | ||
|
|
||
| final String taskName = "taskName"; | ||
| final String operation = "operation"; | ||
| final Map<String, String> taskTags = mkMap(mkEntry("tkey", "value")); | ||
|
|
||
| final String processorNodeName = "processorNodeName"; | ||
| final Map<String, String> nodeTags = mkMap(mkEntry("nkey", "value")); | ||
|
|
||
| final Sensor parent1 = metrics.taskLevelSensor(taskName, operation, Sensor.RecordingLevel.DEBUG); | ||
| addAvgMaxLatency(parent1, PROCESSOR_NODE_METRICS_GROUP, taskTags, operation); | ||
| addInvocationRateAndCount(parent1, PROCESSOR_NODE_METRICS_GROUP, taskTags, operation); | ||
|
|
||
| final int numberOfTaskMetrics = registry.metrics().size(); | ||
|
|
||
| final Sensor sensor1 = metrics.nodeLevelSensor(taskName, processorNodeName, operation, Sensor.RecordingLevel.DEBUG, parent1); | ||
| addAvgMaxLatency(sensor1, PROCESSOR_NODE_METRICS_GROUP, nodeTags, operation); | ||
| addInvocationRateAndCount(sensor1, PROCESSOR_NODE_METRICS_GROUP, nodeTags, operation); | ||
|
|
||
| assertThat(registry.metrics().size(), greaterThan(numberOfTaskMetrics)); | ||
|
|
||
| metrics.removeAllNodeLevelSensors(taskName, processorNodeName); | ||
|
|
||
| assertThat(registry.metrics().size(), equalTo(numberOfTaskMetrics)); | ||
|
|
||
| final Sensor parent2 = metrics.taskLevelSensor(taskName, operation, Sensor.RecordingLevel.DEBUG); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this used for? Sensor
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They should be, but in reality the same parent sensor is (re)registered each time a child sensor is created, so I wanted to (idempotently) create a second parent sensor to make sure there's no extra references. |
||
| addAvgMaxLatency(parent2, PROCESSOR_NODE_METRICS_GROUP, taskTags, operation); | ||
| addInvocationRateAndCount(parent2, PROCESSOR_NODE_METRICS_GROUP, taskTags, operation); | ||
|
|
||
| assertThat(registry.metrics().size(), equalTo(numberOfTaskMetrics)); | ||
|
|
||
| final Sensor sensor2 = metrics.nodeLevelSensor(taskName, processorNodeName, operation, Sensor.RecordingLevel.DEBUG, parent2); | ||
| addAvgMaxLatency(sensor2, PROCESSOR_NODE_METRICS_GROUP, nodeTags, operation); | ||
| addInvocationRateAndCount(sensor2, PROCESSOR_NODE_METRICS_GROUP, nodeTags, operation); | ||
|
|
||
| assertThat(registry.metrics().size(), greaterThan(numberOfTaskMetrics)); | ||
|
|
||
| metrics.removeAllNodeLevelSensors(taskName, processorNodeName); | ||
|
|
||
| assertThat(registry.metrics().size(), equalTo(numberOfTaskMetrics)); | ||
|
|
||
| metrics.removeAllTaskLevelSensors(taskName); | ||
|
|
||
| assertThat(registry.metrics().size(), equalTo(0)); | ||
| } | ||
|
|
||
| @Test | ||
|
|
@@ -115,21 +178,21 @@ public void testTotalMetricDoesntDecrease() { | |
| final String operation = "op"; | ||
|
|
||
| final Sensor sensor = streamsMetrics.addLatencyAndThroughputSensor( | ||
| scope, | ||
| entity, | ||
| operation, | ||
| Sensor.RecordingLevel.INFO | ||
| scope, | ||
| entity, | ||
| operation, | ||
| Sensor.RecordingLevel.INFO | ||
| ); | ||
|
|
||
| final double latency = 100.0; | ||
| final MetricName totalMetricName = metrics.metricName( | ||
| "op-total", | ||
| "stream-scope-metrics", | ||
| "", | ||
| "client-id", | ||
| "", | ||
| "scope-id", | ||
| "entity" | ||
| "op-total", | ||
| "stream-scope-metrics", | ||
| "", | ||
| "client-id", | ||
| "", | ||
| "scope-id", | ||
| "entity" | ||
| ); | ||
|
|
||
| final KafkaMetric totalMetric = metrics.metric(totalMetricName); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch!