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
Cloud Monitoring: Reduce request size when listing labels #44365
Conversation
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.
Let me know if I understood this properly:
Before, all labels were added to all frames, which caused big response sizes. Now only the labels related to a frame are added and in the fronted we evaluate all the frames (rather than the first) to look for all the different labels.
The approach looks good to me, we should add test to ensure that we are enforcing this behavior. Letting @sunker to also review this in case there is something I am missing.
.filter((p) => !!p) | ||
.reduce((acc, labels) => { | ||
for (let key in labels) { | ||
if (acc[key]) { |
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.
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.
That's good point. I didn't check multiple Group bys.
I fixed it in 1b4ed42 .
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.
Thanks for opening this PR @mtanda! Also think the approach looks good. Just fix the comments that we've added. Would also be great with a test that verifies the merging of labels in the datasource.ts file.
@@ -179,7 +179,18 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend< | |||
const dataQueryResponse = toDataQueryResponse({ | |||
data: data, | |||
}); | |||
return dataQueryResponse?.data[0]?.meta?.custom?.labels ?? {}; | |||
return _map(dataQueryResponse?.data, 'meta.custom.labels') |
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.
No need to import map
from lodash - just use dataQueryResponse?.data.map((f) => f.meta.custom.labels)
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.
Thanks for advice, I tend to use lodash...
I fixed it in 5cf1cdf .
.reduce((acc, labels) => { | ||
for (let key in labels) { | ||
if (acc[key]) { | ||
acc[key].push(...labels[key]); |
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.
You just want to push the key, or am I missing something?
acc[key].push(labels[key])
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.
Yes, I do that. I think it is only way to reduce response size with plugin sdk. |
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.
LGTM, just one minor comment to simplify the frontend code.
const labels = dataQueryResponse?.data | ||
.map((f) => f.meta?.custom?.labels) | ||
.filter((p) => !!p) | ||
.reduce((acc, labels) => { | ||
for (let key in labels) { | ||
if (!acc[key]) { | ||
acc[key] = new Set<string>(); | ||
} | ||
acc[key].add(labels[key]); | ||
} | ||
return acc; | ||
}, {}); | ||
return Object.fromEntries( | ||
Object.entries(labels).map((l: any) => { | ||
l[1] = Array.from(l[1]); | ||
return l; | ||
}) | ||
); |
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.
A slightly simpler solution:
const labels = dataQueryResponse?.data | |
.map((f) => f.meta?.custom?.labels) | |
.filter((p) => !!p) | |
.reduce((acc, labels) => { | |
for (let key in labels) { | |
if (!acc[key]) { | |
acc[key] = new Set<string>(); | |
} | |
acc[key].add(labels[key]); | |
} | |
return acc; | |
}, {}); | |
return Object.fromEntries( | |
Object.entries(labels).map((l: any) => { | |
l[1] = Array.from(l[1]); | |
return l; | |
}) | |
); | |
const labels = dataQueryResponse?.data | |
.map((f) => f.meta?.custom?.labels) | |
.filter((p) => !!p) | |
.reduce((acc, labels) => { | |
for (let key in labels) { | |
if (!acc[key]) { | |
acc[key] = []; | |
} | |
if (labels[key] && !acc[key].includes(labels[key])) { | |
acc[key].push(labels[key]); | |
} | |
} | |
return acc; | |
}, {}); | |
return labels; |
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.
(I also noticed that some labels were empty, that code removes those)
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.
Thanks for advice!
Yes, using includes() is simpler.
But, I don’t want to use O(n) function in loop.
In some env, I guess the number of labels is too big. (I may worry too much)
Using Set is intended.
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.
In our env, Cloud Monitoring record more than 1000 pod_name labels.
I think Set is faster than includes() if list is long.
https://www.measurethat.net/Benchmarks/Show/16868/1/includes-vs-has-20220126
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.
I am not sure if the performance benefit goes away with the later loop but anyway it's fine
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.
Thanks for the patch!
(cherry picked from commit d1083b9)
Thanks for merge! |
What this PR does / why we need it:
Cloud Monitoring amplify response size from v8.3.
It cause memory shortage and crash in some environment.
By splitting meta data and relocate it to each frames, the response size could be reduced.
I tested this change locally, and confirm that response size is significantly reduced. (63.06MB -> 3.60MB)
Which issue(s) this PR fixes:
Fixes #44190
Special notes for your reviewer: