Skip to content

KAFKA-8578: Add basic functionality to expose RocksDB metrics#6979

Merged
guozhangwang merged 9 commits into
apache:trunkfrom
cadonna:AK8578-RocksDB-metrics-basics
Aug 2, 2019
Merged

KAFKA-8578: Add basic functionality to expose RocksDB metrics#6979
guozhangwang merged 9 commits into
apache:trunkfrom
cadonna:AK8578-RocksDB-metrics-basics

Conversation

@cadonna

@cadonna cadonna commented Jun 21, 2019

Copy link
Copy Markdown
Member
  • Adds RocksDBMetrics class that provides methods to get
    sensors from the Kafka metrics registry and to setup the
    sensors to record RocksDB metrics
  • Extends StreamsMetricsImpl with functionality to add the
    required metrics to the sensors.

Committer Checklist (excluded from commit message)

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

- Adds `RocksDBMetrics` class that provides methods to get
  sensors from the Kafka metrics registry and to setup the
  sensors to record RocksDB metrics
- Extends `StreamsMetricsImpl` with functionality to add the
  required metrics to the sensors.
@cadonna

cadonna commented Jun 21, 2019

Copy link
Copy Markdown
Member Author

@mjsax mjsax added the streams label Jun 21, 2019
return tagMap;
}

public Map<String, String> storeLevelTagMap(final String taskName, final String storeType, final String storeName) {

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: line to long (break each parameter in it's own line)

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 line is exactly 120 characters long as allowed by the coding guidelines. ;-)

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.

Can we just add https://checkstyle.sourceforge.io/config_sizes.html#LineLength so we never have to have this discussion again? :)

}

public Map<String, String> taskLevelTagMap(final String taskName) {
final Map<String, String> tagMap = threadLevelTagMap();

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.

In threadLevelTagMap(String...) there is a check:

        if (tags != null) {
            if ((tags.length % 2) != 0) {
                throw new IllegalArgumentException("Tags needs to be specified in key-value pairs");
            }

Should we do the same 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.

I am not sure I can follow. We do not have a parameter String... tags here. What should we check?

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.

Actually, I'm not sure what's going on with threadLevelTagMap(String...).

It has exactly one usage, which is streamsMetrics.threadLevelTagMap(TASK_ID_TAG, ALL_TASKS) which seems to be doing exactly the same thing this method is doing.

Maybe we can just get rid of threadLevelTagMap(String...) and migrate the usage to this method?

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.

streamsMetrics.threadLevelTagMap(TASK_ID_TAG, ALL_TASKS) is used for a parent sensor that will be removed as part of KIP-444. When the that sensor will be removed also streamsMetrics.threadLevelTagMap(TASK_ID_TAG, ALL_TASKS) and the corresponding method will disappear. I would like to leave it for the future PR, since that code is not touched in this PR.

}

public Map<String, String> storeLevelTagMap(final String taskName, final String storeType, final String storeName) {
final Map<String, String> tagMap = taskLevelTagMap(taskName);

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 above

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.

As above

final String storeName) {
final Sensor sensor = streamsMetrics
.storeLevelSensor(taskName, storeName, BYTES_WRITTEN_TO_DB, RecordingLevel.DEBUG);
addAmountRateAndTotalMetricsToSensor(sensor,

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: for method calls, we usually format like this:

addAmountRateAndTotalMetricsToSensor(
    sensor,
...);

Breaking the first parameter already reduced line length and seems preferable.

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.

Done

streamsMetrics.storeLevelTagMap(taskName,
STORE_TYPE_PREFIX + storeType, storeName),
BYTES_WRITTEN_TO_DB,
"Average per-second number of bytes written to the RocksDB state store",

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: Average number of bytes written per-second to the RocksDB state store ?

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.

Ack

final String storeName) {
final Sensor sensor = streamsMetrics
.storeLevelSensor(taskName, storeName, BYTES_READ_FROM_DB, RecordingLevel.DEBUG);
addAmountRateAndTotalMetricsToSensor(sensor,

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 above

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.

Done

.storeLevelSensor(taskName, storeName, BYTES_WRITTEN_TO_DB, RecordingLevel.DEBUG);
addAmountRateAndTotalMetricsToSensor(sensor,
STATE_LEVEL_GROUP,
streamsMetrics.storeLevelTagMap(taskName,

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 above

streamsMetrics.storeLevelTagMap(taskName,
STORE_TYPE_PREFIX + storeType, storeName),
BYTES_READ_FROM_DB,
"Average per-second number of bytes read from the RocksDB state store",

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 above

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.

Ack

public void shouldAddAmountRateAndSum() {
final MockTime time = new MockTime(0);

addAmountRateAndTotalMetricsToSensor(sensor, group, tags, metricNamePrefix, description1, description2);

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 think it is confusing to import methods under test (makes it unclear if this is a "setup" method -- might be better to not use static imports) ?

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.

Ack

final double value2 = 18.0;
sensor.record(value2, time.milliseconds());
assertThat(metric.measurable().measure(new MetricConfig(), time.milliseconds()),
equalTo(initialValue + value1 + value2));

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.

Where does initialValue come from? For example: shouldAddAvgAndTotalMetricsToSensor add the sensor and calls verifySumMetric -- why is the initial sum not zero?

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 initial value is not zero, because in shouldAddAvgAndTotalMetricsToSensor two verifications are called, one verifies the Avg metric and the other the Sum metric. The first verification records two values and the second verification also records two values. Inside the metric the values are computed over samples. All four values added in the verifications are added to the samples over which the metric is computed. That means that the two values added for the first verification are already in the metric sample when the second verification is called. Hence, the initial value in the second verification is the sum of the two values added to the metric in the first verification.

I changed the test to get rid of the initial value. Now, I advance mock time as long as it needs to get empty samples.


public static final String THREAD_ID_TAG = "client-id";
public static final String TASK_ID_TAG = "task-id";
public static final String STORE_ID_TAG = "state-id";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

should it be called store-id then?

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 is to be consistent with existing state store-level ids.

return sensor;
}

public static Sensor memtableBytesFlushedSensor(final StreamsMetricsImpl streamsMetrics,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One thing I would suggest we do is to create an intermediate struct to store all the parameters, in case later we need to add more fields for sensor creation.

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.

Good idea! Done!

private static final String MEMTABLE_BYTES_FLUSHED = "memtable-bytes-flushed";
private static final String MEMTABLE_HIT_RATIO = "memtable-hit" + RATIO_SUFFIX;
private static final String MEMTABLE_FLUSH_TIME = "memtable-flush-time";
private static final String WRITE_STALL_DURATION = "write-stall-duration";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I would suggest we co-locate the description with metrics and refactor out the sensor creation part, this may help reduce code redundancy.

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 am afraid, I cannot follow. Could you elaborate?

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.

Maybe @abbccdda was saying to store the description strings in static final fields as well? I'd agree with this, just to be sure that we don't waste memory on duplicate description strings.

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.

Does this make any difference since all description strings are literals in static methods?

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.

Yes, each time the method is invoked (I.e., once per store), a separate copy of the string is placed on the heap. I previously didn't think this would be a big factor, but someone in the community profiled the memory usage of a long-running topology and found that these strings tend to accumulate over time.

There's no need to worry about this for short-scoped strings like exception messages, but metrics are long-lived objects, and we benefit from making them static constants.

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.

Oh, I see makes sense.


@Test
public void shouldAddAmountRateAndSum() {
final MockTime time = new MockTime(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How about making time a private field and do a setUp call to reinitialize it every time?

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.

Done

assertThat(metrics.metrics().size(), equalTo(2 + 1)); // one metric is added automatically in the constructor of Metrics
}

private void verifySumMetric(final Metrics metrics,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It's more reusable if we make value1 and value2 both parameters. Maybe we could pass a List along with initialValue in this case?

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 would like to leave this method as it is because it suffices to use two values to verify that the statistical function set in the metric is a sum. IMO a test should be as simple as possible to avoid errors. Additionally, the expected sum would not only depend on the list of values but also on the instance of MetricConfig. This dependency would unnecessarily complicate the logic of this verification.

sensor.record(value1, time.milliseconds());
final double value2 = 18.0;
sensor.record(value2, time.milliseconds());
time.sleep(30000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This sleep is a bit too long for a unit test, could we consider avoiding it?

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.

This is NOT an actual sleep. This call advances the mocked time by 30 seconds. It does not wait at all.

replayAndVerify(sensorCreator);
}

private void verifyRateSensor(final String metricNamePrefix,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: I slightly doubt whether these exact match tests are necessary

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.

Could you elaborate on your doubts? How should I otherwise test, if the methods in RocksDBMetrics create the sensors with the correct name, tags and metrics? Please let me know, if you have a better idea.

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

@cadonna I made a pass overall looks good I only have one minor comment in addition to the other comments.

sensor.record(value1, time.milliseconds());
final double value2 = 18.0;
sensor.record(value2, time.milliseconds());
time.sleep(30000);

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.

here it might work better to use TestUtils.waitForCondition instead of an arbitrary sleep call

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.

This is NOT an actual sleep. This call advances the mocked time by 30 seconds. It does not wait at all.

@bbejeck

bbejeck commented Jun 24, 2019

Copy link
Copy Markdown
Member

Java 8 and Java 11 failed, test results already cleaned up.

Retest this please


public static final String THREAD_ID_TAG = "client-id";
public static final String TASK_ID_TAG = "task-id";
public static final String STORE_ID_TAG = "state-id";

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 is to be consistent with existing state store-level ids.

"The average per-second number of " + operation);
}

public static void addAmountRateAndTotalMetricsToSensor(final Sensor sensor,

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 is not part of the PR but I realized that CumulativeCount is in streams.processor.internals.metrics but not in common.metrics.stats. Is this intentional? @vvcephei

@vvcephei vvcephei Jul 9, 2019

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.

IIRC, it was done to avoid a KIP.

Of course, that may or may not have been the right thing to do, but I believe it was the idea... Do you think we should move it?

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.

Ok, I took a closer look and had a bit of a flash-back to how confusing these metrics are... Maybe #7057 will help.

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.

Thank you @vvcephei !


public Map<String, String> storeLevelTagMap(final String taskName, final String storeType, final String storeName) {
final Map<String, String> tagMap = taskLevelTagMap(taskName);
tagMap.put(storeType + STORE_ID_TAG, storeName);

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.

Are the storeType supposed to have the dash already? If not this should be storeType + "-" + STORE_ID_TAG.

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.

Good point! I think I am going to change this to be consistent with the other labels.

final String storeName) {
final Sensor sensor = streamsMetrics
.storeLevelSensor(taskName, storeName, COMPACTION_TIME + MIN_SUFFIX, RecordingLevel.DEBUG);
addValueMetricToSensor(sensor,

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.

I'm a bit confused here for max / min we are creating a sensor with type Value still, but since I did not see how the record() is going to be invoked maybe I'm just wrong.. otherwise, could we just use a similar function like addAvgAndMax?

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.

For the RocksDB statistics that come in the form of histograms, we already get the min, max, and average values from RocksDB. We still need to decide if we should reset the histogram after each recording to have
kind of a moving window semantic or if we are fine with the histograms from the start of the application. WDYT?

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.

Just chiming in, I think we're just defining the metrics in this PR and then actually recording them later. We might change the actual metric type later on when we look at how it's going to actually get recorded, so maybe we shouldn't worry too much about the selected metric implementation right now.

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.

Agreed

}

public Map<String, String> taskLevelTagMap(final String taskName) {
final Map<String, String> tagMap = threadLevelTagMap();

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.

Actually, I'm not sure what's going on with threadLevelTagMap(String...).

It has exactly one usage, which is streamsMetrics.threadLevelTagMap(TASK_ID_TAG, ALL_TASKS) which seems to be doing exactly the same thing this method is doing.

Maybe we can just get rid of threadLevelTagMap(String...) and migrate the usage to this method?

return tagMap;
}

public Map<String, String> storeLevelTagMap(final String taskName, final String storeType, final String storeName) {

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.

Can we just add https://checkstyle.sourceforge.io/config_sizes.html#LineLength so we never have to have this discussion again? :)

private static final String MEMTABLE_BYTES_FLUSHED = "memtable-bytes-flushed";
private static final String MEMTABLE_HIT_RATIO = "memtable-hit" + RATIO_SUFFIX;
private static final String MEMTABLE_FLUSH_TIME = "memtable-flush-time";
private static final String WRITE_STALL_DURATION = "write-stall-duration";

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.

Maybe @abbccdda was saying to store the description strings in static final fields as well? I'd agree with this, just to be sure that we don't waste memory on duplicate description strings.

"The average per-second number of " + operation);
}

public static void addAmountRateAndTotalMetricsToSensor(final Sensor sensor,

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.

Ok, I took a closer look and had a bit of a flash-back to how confusing these metrics are... Maybe #7057 will help.

sensor.add(new MetricName(name, group, description, tags), new Value());
}

public static void addAvgAndTotalMetricsToSensor(final Sensor sensor,

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.

Suggested change
public static void addAvgAndTotalMetricsToSensor(final Sensor sensor,
public static void addAvgAndSumMetricsToSensor(final Sensor sensor,

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.

Done

final String storeName) {
final Sensor sensor = streamsMetrics
.storeLevelSensor(taskName, storeName, COMPACTION_TIME + MIN_SUFFIX, RecordingLevel.DEBUG);
addValueMetricToSensor(sensor,

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.

Just chiming in, I think we're just defining the metrics in this PR and then actually recording them later. We might change the actual metric type later on when we look at how it's going to actually get recorded, so maybe we shouldn't worry too much about the selected metric implementation right now.

verifyAll();
verify(StreamsMetricsImpl.class);

assertThat(sensor, is(this.sensor));

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.

Hey, I'm sorry, but can you explain what's going on here? Sensor doesn't override equals, so I'm not seeing how this assertion works.

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.

Here I am just verifying that the methods in RocksDBMetrics pass through the sensor they get from the methods in the StreamsMetricImpl mock. It is an equality check on the reference. Before verifying the sensor, I also verify through the mock whether the metrics with the correct names and tags are added to the sensor.

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.

Oh, right, I forgot that the metrics registry returns the same copy of the sensor when all the name, description, and tags are the same... Thanks.

@cadonna

cadonna commented Jul 10, 2019

Copy link
Copy Markdown
Member Author

Failures unrelated
Retest this, please

@cadonna

cadonna commented Jul 12, 2019

Copy link
Copy Markdown
Member Author

Retest this, please

"The average per-second number of " + operation);
}

public static void addAmountRateAndTotalMetricsToSensor(final Sensor sensor,

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.

Thank you @vvcephei !

addTotalMetricToSensor(sensor, group, tags, operation, descriptionOfTotal);
}

public static void addAmountRateMetricToSensor(final Sensor sensor,

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 is not for this PR, but: since in #7057 we are cleaning up the confusing names shall we do the same for function names as well as a follow-up? Also the existing function names do not have ..ToSensor suffix, could we make it consistent (I'm fine with either way, just want to do the same for new and existing functions)?

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.

To make the function name consistent with the Stat name, should this be addRateOfSum?

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.

This is not for this PR, but: since in #7057 we are cleaning up the confusing names shall we do the same for function names as well as a follow-up? Also the existing function names do not have ..ToSensor suffix, could we make it consistent (I'm fine with either way, just want to do the same for new and existing functions)?

I agree with you that we should be consistent. I just did not want to make this PR bigger than needed since it is already quite big. I will open a refactoring PR for this.

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.

To make the function name consistent with the Stat name, should this be addRateOfSum?

Done

new Rate(TimeUnit.SECONDS, new Sum()));
}

public static void addTotalMetricToSensor(final Sensor sensor,

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.

Similarly: addSum?

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.

Done

}
}

@Test

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 is a meta comment: for SampledStat their recorded values can vary based on the windowing itself, so in unit test it may not always has the exact value, i.e. asserting equalTo(value) may make this flaky, whereas just testing it is non-zero is sufficient.

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.

IIUC, since SampledStat metrics do not maintain any clock internally and I use MockTime in the unit tests, the values recorded in SampledStat should be deterministic. Please, correct me if I am missing anything.

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.

If we are using MockTime then it should be fine.

"Total number of bytes read from the RocksDB state store";
private static final String MEMTABLE_BYTES_FLUSHED_RATE_DESCRIPTION =
"Average number of bytes flushed per second from the memtable to disk";
private static final String MEMTABLE_BYTES_FLUSHED_AVG_DESCRIPTION =

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.

The description Total number ... seems incorrect for AVG?

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.

Oh... Thank you! Actually, it is the other way around. The description is correct, but the variable name is wrong.

"Minimum time spent on flushing the memtable to disk in ms";
private static final String MEMTABLE_FLUSH_TIME_MAX_DESCRIPTION =
"Maximum time spent on flushing the memtable to disk in ms";
private static final String WRITE_STALL_DURATION_AVG_DESCRIPTION = "Moving average duration of write stalls in ms";

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.

Moving average duration may be a bit confusing to readers, maybe just Average duration of ...

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 will change it to Average duration to be consistent with the other average metrics. However, I think we risk wrong expectations on user side if we do not improve the descriptions of the metrics. Especially, with having compaction-time-avg which is not a moving average, but it has the following description Average time spent on compaction in ms.

@cadonna

cadonna commented Jul 31, 2019

Copy link
Copy Markdown
Member Author

Retest this, please

1 similar comment
@cadonna

cadonna commented Aug 1, 2019

Copy link
Copy Markdown
Member Author

Retest this, please

@guozhangwang
guozhangwang merged commit a7d0fdd into apache:trunk Aug 2, 2019
@guozhangwang

Copy link
Copy Markdown
Contributor

Merged to trunk, thanks @cadonna !!

@cadonna
cadonna deleted the AK8578-RocksDB-metrics-basics branch October 21, 2019 11:40
@mjsax mjsax added the kip Requires or implements a KIP label Jun 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kip Requires or implements a KIP streams

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants