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

Cloud Monitoring: Reduce request size when listing labels #44365

Merged
merged 6 commits into from Jan 26, 2022

Conversation

mtanda
Copy link
Collaborator

@mtanda mtanda commented Jan 24, 2022

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:

@CLAassistant
Copy link

CLAassistant commented Jan 24, 2022

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@andresmgot andresmgot left a 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.

pkg/tsdb/cloudmonitoring/time_series_query.go Show resolved Hide resolved
.filter((p) => !!p)
.reduce((acc, labels) => {
for (let key in labels) {
if (acc[key]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

you would need to avoid pushing labels that are already there:

Screenshot from 2022-01-24 12-00-13

Copy link
Collaborator Author

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 .

Copy link
Contributor

@sunker sunker left a 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')
Copy link
Contributor

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)

Copy link
Collaborator Author

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]);
Copy link
Contributor

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])

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is wrong code.
And I notice that response format is not appropriate.

The value type of label map should be string, not string list.
I fixed the response format in fc7bb7c .

And, fixed frontend in 1b4ed42 .

@mtanda
Copy link
Collaborator Author

mtanda commented Jan 25, 2022

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.

Yes, I do that. I think it is only way to reduce response size with plugin sdk.

@mtanda mtanda marked this pull request as ready for review January 25, 2022 07:18
@mtanda mtanda requested a review from a team as a code owner January 25, 2022 07:18
@mtanda mtanda requested review from vickyyyyyyy and removed request for a team January 25, 2022 07:18
Copy link
Contributor

@andresmgot andresmgot left a 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.

Comment on lines 182 to 199
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;
})
);
Copy link
Contributor

Choose a reason for hiding this comment

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

A slightly simpler solution:

Suggested change
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;

Copy link
Contributor

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)

Copy link
Collaborator Author

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.

Copy link
Collaborator Author

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.
Screenshot 2022-01-26 091158

I think Set is faster than includes() if list is long.
https://www.measurethat.net/Benchmarks/Show/16868/1/includes-vs-has-20220126

Copy link
Contributor

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

@andresmgot andresmgot added the backport v8.3.x Mark PR for automatic backport to v8.3.x label Jan 26, 2022
@andresmgot andresmgot modified the milestones: 8.3.5, 8.3.6 Jan 26, 2022
Copy link
Contributor

@andresmgot andresmgot left a 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!

@andresmgot andresmgot changed the title reduce response size for Cloud Monitoring label response Cloud Monitoring: Reduce request size when listing labels Jan 26, 2022
@andresmgot andresmgot merged commit d1083b9 into grafana:main Jan 26, 2022
grafanabot pushed a commit that referenced this pull request Jan 26, 2022
andresmgot pushed a commit that referenced this pull request Jan 26, 2022
…44473)

(cherry picked from commit d1083b9)

Co-authored-by: Mitsuhiro Tanda <mitsuhiro.tanda@gmail.com>
@mtanda
Copy link
Collaborator Author

mtanda commented Jan 26, 2022

Thanks for merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Grafana crash due to huge response for Cloud Monitoring HEADERS request
5 participants