Skip to content
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

Adding new metrics for SAI in nodetool tablestats command. #3742

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from

Conversation

sunil9977
Copy link
Contributor

CASSANDRA-20026
Adding below metrics in nodetool tablestats command -

  1. SAI local query latency (mean)
  2. SAI post-filtering latency (mean)
  3. SAI space used (bytes)
  4. SAI SSTable indexes hit per query (mean)
  5. SAI index segments hit per query (mean)
  6. SAI rows filtered per query (mean)
  7. SAI local total query timeouts
  8. SAI queryable/total indexes

@maedhroz maedhroz self-requested a review December 13, 2024 21:48
"\tSAI SSTable indexes hit per query (mean): 0.0\n" +
"\tSAI index segments hit per query (mean): 0.0\n" +
"\tSAI rows filtered per query (mean): 0.0\n" +
"\tSAI local total query timeouts: 0\n" +
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I guess we could just make this "local query timeouts" and leave out the "total". It's fairly obvious this is a count and not a rate...

(see also below if you do change it)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Corrected the name.

" \"average_live_cells_per_slice_last_five_minutes\" : 5.0,\n" +
" \"local_read_latency_ms\" : \"1.000\",\n" +
" \"sstable_count\" : 1000,\n" +
" \"sai_Index_Segments_Hit\" : 0.0,\n" +
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Any way we can keep things lower case for consistency?

"\tSAI index segments hit per query (mean): 0.0\n" +
"\tSAI rows filtered per query (mean): 0.0\n" +
"\tSAI local total query timeouts: 0\n" +
"\tSAI queryable/total indexes: null\n" +
Copy link
Contributor

Choose a reason for hiding this comment

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

We should have a few of these test tables present non-zero/null values. Here are some reasonable examples:

SAI local query latency (mean): 10.000 ms
SAI post-filtering latency (mean): 1.000 ms
SAI space used (bytes): 128000000
SAI SSTable indexes hit per query (mean): 3.5
SAI index segments hit per query (mean): 4.0
SAI rows filtered per query (mean): 55.0
SAI local total query timeouts: 4
SAI queryable/total indexes: 5/5

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added test table5 with SAI metrics.

" \"sai_queryable_total_indexes\" : \"0/0\",\n" +
" \"droppable_tombstone_ratio\" : \"0.66667\",\n" +
" \"compression_metadata_off_heap_memory_used\" : \"1\",\n" +
" \"sai_Rows_Filtered\" : \"NaN\",\n" +
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: still mixed case?

return "PerQuery";
case "PostFilteringReadLatency":
case "TotalQueryTimeouts":
return "TableQueryMetrics";
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have TableQueryMetrics.TABLE_QUERY_METRIC_TYPE and TableStateMetrics.TABLE_STATE_METRIC_TYPE that we can reuse here, but I feel like it would be a good time to do something similar for "IndexGroupMetrics" (in IndexGroupMetrics) and "PerQuery" (in PerQueryMetrics).

I wouldn't say we have to extend this to the individual metric names, as we shouldn't be changing those anyway (with them being a user-facing thing).

@@ -1892,7 +1892,66 @@ public Object getThreadPoolMetric(String pathName, String poolName, String metri
}
}

/**
public Object getSAIIndexMetrics(String ks, String cf, String metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

}
}

private Object getMetricValue(String metricName, ObjectName oName) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

}
}

private String getScopeForMetric(String metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

public long TotalQueryTimeouts;
public int TotalIndexCount;
public int TotalQueryableIndexCount;
public String TotalQueryableIndexRatio;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit/style: For the above, make sure to start field names w/ lower-case letter

Copy link
Contributor

Choose a reason for hiding this comment

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

...or we could just prefix them all with sai, which I was going to suggest anyway, given some of them are pretty general, like disk used bytes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added prefix as sai.

}
else if(sortKey.equals("disk_used_bytes"))
{
return sign * ((String) stx.DiskUsedBytes).compareTo((String) sty.DiskUsedBytes);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we use compareFileSizes() here?

{
result = compareDoubles(stx.PostFilteringReadLatencyms, sty.PostFilteringReadLatencyms);
}
else if(sortKey.equals("disk_used_bytes"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be "sai_disk_used_bytes"?

}
else if(sortKey.equals("TotalQueryableIndexCount"))
{
return sign * ((int) stx.TotalQueryableIndexCount);
Copy link
Contributor

Choose a reason for hiding this comment

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

For TotalIndexCount and TotalQueryableIndexCount, are we actually comparing anything here?

mpTable.put("sai_Rows_Filtered",table.RowsFiltered);
mpTable.put("sai_total_query_timeouts",table.TotalQueryTimeouts);
mpTable.put("total_index_count",table.TotalIndexCount);
mpTable.put("queryable_index_count",table.TotalQueryableIndexCount);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: We should probably prefix these two with sai_ to be safe.

}
}

private Object getMetricValue(String metricName, ObjectName oName) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private Object getMetricValue(String metricName, ObjectName oName) throws IOException {
private Object getSaiMetricValue(String metricName, ObjectName oName) throws IOException {

@@ -1892,7 +1892,66 @@ public Object getThreadPoolMetric(String pathName, String poolName, String metri
}
}

/**
public Object getSAIIndexMetrics(String ks, String cf, String metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public Object getSAIIndexMetrics(String ks, String cf, String metricName) {
public Object getSaiMetric(String ks, String cf, String metricName) {

}
}

private String getScopeForMetric(String metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private String getScopeForMetric(String metricName) {
private String getSaiMetricScope(String metricName) {

Set<ObjectName> matchingMBeans = mbeanServerConn.queryNames(oName, null);
if (matchingMBeans.isEmpty()) {
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: might as well just avoid the braces for this if

@@ -1892,7 +1892,66 @@ public Object getThreadPoolMetric(String pathName, String poolName, String metri
}
}

/**
public Object getSAIIndexMetrics(String ks, String cf, String metricName) {
try {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

}

return getMetricValue(metricName, oName);
} catch (MalformedObjectNameException e) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

}

private Object getMetricValue(String metricName, ObjectName oName) throws IOException {
switch (metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

}

private String getScopeForMetric(String metricName) {
switch (metricName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: { on newline

@maedhroz
Copy link
Contributor

One thing I think we want to double-check on is that we don't show these stats for system tables, as they shouldn't have SAI indexes.

return null;

return getSaiMetricValue(metricName, oName);
} catch (MalformedObjectNameException e)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit/formatting: For everything below, newlines after } and before the catch

out.println("");
}

private boolean isSystemKeyspaces(String keyspaceName) {
return SchemaConstants.isSystemKeyspace(keyspaceName);

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: unnecessary newline

out.println("");
}

private boolean isSystemKeyspaces(String keyspaceName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: newline for {

Object totalQueryableIndexCount = probe.getSaiMetric(keyspaceName, tableName, "TotalQueryableIndexCount");
int saiTotalQueryableIndexCount = (totalQueryableIndexCount != null) ? (int) totalQueryableIndexCount : 0;

statsTable.saiTotalQueryableIndexRatio = String.format("%d/%d", saiTotalIndexCount, saiTotalQueryableIndexCount);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we avoid the entire block above if we're looking at a system keyspace? We've got a check at print-time in TableStatsPrinter, but it seems like we might as well avoid hitting the probe here if we're not going to print the info anyway?

statsKeyspace.tables.add(statsTable);
}
keyspaces.add(statsKeyspace);
}
}

private boolean isSystemKeyspaces(String keyspaceName)
{
return SchemaConstants.isSystemKeyspace(keyspaceName);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Here and in TableStatsPrinter we could probably just inline the SchemaConstants.isSystemKeyspace() call. It's only used once in both classes anyway...

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.

2 participants