Skip to content

Make mergeQueryable more generically usable #4117

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

Conversation

simonswine
Copy link
Contributor

@simonswine simonswine commented Apr 26, 2021

What this PR does:

This change allows to use a mergeQueryable (by external projects), to aggregate results from multiple underlying Queryables.

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]

@simonswine simonswine force-pushed the 20210423_make-merge-queryable-more-generic branch from ea0f085 to 34d8b75 Compare April 27, 2021 17:11
@simonswine simonswine marked this pull request as ready for review April 27, 2021 17:15
Copy link
Contributor

@trevorwhitney trevorwhitney left a comment

Choose a reason for hiding this comment

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

Just a few minor things, nothing blocking. I did have a lot of trouble understanding what each of those test cases was testing, particularly with the nested table tests in selectorCases, so it was hard to verify the new logic was tested.

// ensure to byPass a single querier and avoid adding a tenant label to
// ensure backward compatabiltiy when enabling multi-tenant query
// federation.
return tenantIDs, queriers, true, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't understand that comment until I read the GenericQuerierCallback further down, maybe worth pulling that boolean into a variable for the sake of naming/clarity on what it does?

Copy link
Contributor 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 the way I rearranged it makes it way clearer

@simonswine
Copy link
Contributor Author

simonswine commented Apr 28, 2021

I did have a lot of trouble understanding what each of those test cases was testing, particularly with the nested table tests in selectorCases, so it was hard to verify the new logic was tested.

@trevorwhitney good point and thanks for diving into depths there. Any ideas how to decouple testing? I couldn't think of a simpler way to ensure the Queryable behaves correctly. I guess part of the problem the defined interfaces contains nested interfaces

@trevorwhitney
Copy link
Contributor

@simonswine I think the biggest logic change to make sure we test is the bypass with single querier logic. That might be tested in the following test case but I wasn't sure:

{
			name:       "single tenant",
			tenants:    []string{"team-a"},
			labelNames: []string{"instance", "tenant-team-a"},
			expectedLabelValues: map[string][]string{
				"instance": {"host1", "host2.team-a"},
			},
		},

@simonswine
Copy link
Contributor Author

@trevorwhitney I think we do test the skip case, as if we wouldn't byPass with a single querier the labelNames would also contain identifyingLabelName in that test case:

  	labelNames: []string{"instance", "tenant-team-a"},

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

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

I think you went too far with making this "generic". I see the value in supplying custom tenant ID label name or prefix for conflicting labels, but the renames seem unnecessary (they are not even complete... there is genericQueryable but mergeQuerier) and make diff too large.

One think that's missing in mergeQueryable is tracing -- I think we should span to it. It can be separate PR.

// byPassWithSingleQuerierUsing determines if it should still be using the
// mergeQuerier (and adding a `identifyingLabelName` label) or if just the
// underlying querier should be returned.
type GenericQuerierCallback func(ctx context.Context, mint int64, maxt int64) (labelValues []string, queriers []storage.Querier, byPassWithSingleQuerier bool, err error)
Copy link
Contributor

Choose a reason for hiding this comment

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

In what scenario does it make sense for callback to return byPassWithSingleQuerier=false?

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 think in general the callback should be returning byPassWithSingleQuerier=false. Even though we only have a single cluster we are querying from, we still want the idLabelName on the results.

In my use case I want to able to aggregate results from multiple cluster and I want to make sure even if there's only a single cluster returned by the call that this cluster is identifiable using the idLabelName. Once a user adds a second cluster later on, there is no user visible change to the results if we also have the label on the single querier case.

The reason why for tenant federation byPassWithSingleQuerier=true, is so that we don't have a breaking behavior, when enabling tenant federation in a cortex cluster.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even though we only have a single cluster we are querying from, we still want the idLabelName on the results.

Makes sense to me.

The reason why for tenant federation byPassWithSingleQuerier=true, is so that we don't have a breaking behavior, when enabling tenant federation in a cortex cluster.

This feature is still marked as experimental. As long as we properly document the change in the changelog, it's ok to break current behavior, esp. if it is not quite correct. And supporting only single case in the code will be easier. WDYT?

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 think I am less worried about a breaking change in the experimental feature, than the future experience of turning tenant federation on. With having an additonal "id" label in the single user queries, it would be quite disruptive, while otherwise it would be not changing anything. I still think its worthy of keeping.

//cc @jtlisi wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

So just to clarify the breaking change here would be always returning the __tenant_id__ on every single query?

I'm personally fine with that change. I honestly don't see it being a change that bothers people. I also think it would help end users become more familiar with tenancy in Cortex.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly that, once tenant federation is switched on, every query would return a __tenant_id__ label.

OK maybe I was a bit too worried how user facing change it is. I will change this PR accordingly and add a [CHANGE] note to the changelog.

Copy link
Contributor

@pstibrany pstibrany Apr 29, 2021

Choose a reason for hiding this comment

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

Discussed offline. We agreed on keeping the mechanism to bypass mergeQuerier logic when only single tenant is queried. Otherwise all queries would start returning extra labels, when using the feature.

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 have moved byPassWithSingleQuerier to now be a parameter to NewQueryable and added a test case

Copy link
Contributor

Choose a reason for hiding this comment

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

I have moved byPassWithSingleQuerier to now be a parameter to NewQueryable and added a test case

Awesome, I much prefer doing it in the creation function and not the callback

This changes allow to mergeQueryables to be reused in other cases, that
require multiple underlying queryables to be aggregated.

Signed-off-by: Christian Simon <simon@swine.de>
@simonswine simonswine force-pushed the 20210423_make-merge-queryable-more-generic branch from 00ec9b4 to 83b87ce Compare April 29, 2021 10:08
Signed-off-by: Christian Simon <simon@swine.de>
Copy link
Contributor

@jtlisi jtlisi left a comment

Choose a reason for hiding this comment

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

LGTM, I much prefer handling this at instantiation

@simonswine
Copy link
Contributor Author

One think that's missing in mergeQueryable is tracing -- I think we should span to it. It can be separate PR.

That's something I am not particularly familiar, but I think this will be very valuable. Factored this out into #4147

@pstibrany
Copy link
Contributor

That's something I am not particularly familiar, but I think this will be very valuable. Factored this out into #4147

Thanks for creating the issue.

Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

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

Thanks!

@pstibrany pstibrany merged commit b6eea5f into cortexproject:master May 5, 2021
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.

4 participants