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

Proposal: query path tenancy #6320

Merged
merged 25 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2b86f4b
Add 1st version of query path tenancy proposal
douglascamata Apr 26, 2023
8a9ffa3
Update proposal after initial feedback
douglascamata Apr 26, 2023
38c85c1
Add cool picture
douglascamata Apr 26, 2023
2873c12
Include example in cross tenant query complications
douglascamata Apr 26, 2023
d68586b
Improve reasoning for why not using the QFE
douglascamata Apr 26, 2023
908accb
Improve writing in "How" section
douglascamata Apr 26, 2023
52c865e
Fix owner profile link
douglascamata Apr 26, 2023
dc9b64b
Apply suggestions from code review
douglascamata Apr 27, 2023
aa8f20a
Address few more PR review comments
douglascamata Apr 27, 2023
ec47877
Address feedback on flag name text
douglascamata Apr 27, 2023
b14982c
Update diagram
douglascamata Apr 27, 2023
1ba8493
Improve non-goals text
douglascamata Apr 27, 2023
abc44d8
Update diagram
douglascamata Apr 27, 2023
d325493
Update docs/proposals-accepted/202304-query-path-tenancy.md
douglascamata Apr 27, 2023
f7d1dc0
Clarify scenario for pitfalls of current solution
douglascamata Apr 27, 2023
5e12994
Clarify that Store doesn't care about tenant label
douglascamata Apr 27, 2023
c95450e
Add an action plan
douglascamata Apr 28, 2023
c2e5f0e
Mention alternative idea of modifying Store API
douglascamata Apr 28, 2023
e9a6fa2
Merge branch 'main' of github.com:thanos-io/thanos into query-path-te…
douglascamata Apr 28, 2023
cf71fb6
Fix typo
douglascamata May 4, 2023
0001b62
Address lots of feedback on the proposal
douglascamata May 4, 2023
cd34490
Format query path tenancy proposal doc
douglascamata May 4, 2023
98b902b
Add a "Tenancy Model" subsection to "Goals"
douglascamata May 4, 2023
f80384e
Mention header semanthics in comparison with gRPC message field
douglascamata May 4, 2023
300ed71
Improve action plan structure and writing
douglascamata May 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/img/query-path-tenancy-proposal-diagram.svg
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
139 changes: 139 additions & 0 deletions docs/proposals-accepted/202304-query-path-tenancy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
type: proposal
title: Tenancy awareness in query path
status: accepted
owner: douglascamata
menu: proposals-accepted
---

## Tenancy awareness in query path

* **Owners:**
* [@douglascamata](https://github.com/douglascamata)

* **Related Tickets:**
* [Querier: Added native multi-tenancy support](https://github.com/thanos-io/thanos/pull/4141).
* [Proposal: Native Multi-tenancy Support](https://github.com/thanos-io/thanos/pull/4055)

* **Other docs:**
* [Multi-tenancy in Thanos](https://thanos.io/tip/operating/multi-tenancy.md/)

<!--
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
> TL;DR: Give a summary of what this document is proposing and what components it is touching.
>
> *For example: This design doc is proposing a consistent design template for “example.com” organization.*
-->

This design doc proposes to add tenancy awareness in the query path.

## Why

<!--
Provide a motivation behind the change proposed by this design document, give context.

*For example: It’s important to clearly explain the reasons behind certain design decisions in order to have a consensus between team members, as well as external stakeholders. Such a design document can also be used as a reference and knowledge-sharing purposes. That’s why we are proposing a consistent style of the design document that will be used for future designs.*
-->

In a multi-tenant environment, it's important to be able to identify which tenants are experiencing issues and configure (e.g. with different limits) each one of them individually and according to their usage of the platform so that the quality of service can be guaranteed to all the tenants.


### Pitfalls of the current solution

<!--
What specific problems are we hitting with the current solution? Why it’s not enough?

*For example, We were missing a consistent design doc template, so each team/person was creating their own. Because of inconsistencies, those documents were harder to understand, and it was easy to miss important sections. This was causing certain engineering time to be wasted.*
-->

The current lack of tenancy awareness in Thanos' query path makes it impossible to investigate issues related to multi-tenancy without the use of external tools or proxies. For example, it's impossible to determine which tenants are experiencing high latency or high error rates.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved

## Goals

<!--
Goals and use cases for the solution as proposed in [How](#how):

* Allow easy collaboration and decision making on design ideas.
* Have a consistent design style that is readable and understandable.
* Have a design style that is concise and covers all the essential information.
-->

* Allow the query path components to be configurable to identify tenants, opening the way to the implementation per-tenant features on the query path. These features include, but aren't limited to, the following:
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* Per-tenant observability.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* Per-tenant settings. For example, having different limits per tenant, which is a common request.
* Enforce presence of one or more tenant labels in queries.
Copy link
Contributor

Choose a reason for hiding this comment

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

We can achieve these goals by having separate query instances for individual tenants. A valid goal would be simplifying management for multi-tenant setups and pooling resources to reduce waste.

Choose a reason for hiding this comment

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

Don't see any mention of reusing some cortex components that already implement multi-tenancy using an HTTP header. 😦

I wouldn't recommend putting cortex as a dependency. But why not just copy the bits you like here?

we would be happy be deleting code from cortex if it makes it in Thanos 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @friedrichg, can you give us some good pointers for this implementation on the Cortex side? I'm not familiar with Cortex and its features, so I'm very unaware of how it implements things.

If it aligns well with how we want to move forward with this, it'll be great to reuse some code (be it importing or copying) so that both projects benefit from it. I know there are some design differences between the two projects, so let's see what can be done and reused.

Choose a reason for hiding this comment

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

Thanos and Cortex are very similar, both CNCF projects, sort of rivals in the old days. But nowadays Cortex just reuses a bunch of components from thanos. The compactor, the store-gateway, etc. There is too many things in common.

The thing cortex added from the beginning was the multi-tenancy, so we it adds header to all requests, so all components know what tenant is it about.

And like I said importing cortex into thanos is not a good idea, because it was a thing that happened in the past that created circular dependencies. I think is better you just copy what you need and we reuse it in Cortex (As we already do 😃 )

https://cortexmetrics.io/docs/architecture/

Find me in slack cncf #cortex if you want to chat more about 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.

Awesome. I'll get back to this next week and reach out if I have questions or ideas. Thanks. 🙇

Copy link
Member

@bwplotka bwplotka May 3, 2023

Choose a reason for hiding this comment

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

Yea, I think it's good point to mention Cortex way of dealing with this as inspiration, but there is nothing wrong in revisiting this feature and checking if there is anything we could improve before implementing.

Ideally, we could have the same solution, so the tools that works on top of Cortex will work on top of Thanos. That's fair advantage to adopting similar patterns. Another advantage is easier migrations between projects, helpful if we will try to unify projects at some point.

Can we mention this somewhere in the doc (advantage and Cortex pattern)? Thanks!

douglascamata marked this conversation as resolved.
Show resolved Hide resolved

### Audience

<!--
If this is not clear already, provide the target audience for this change.
-->

Any team running Thanos in a multi-tenant environment.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved

## Non-Goals

<!--
* Move old designs to the new format.
* Not doing X,Y,Z.
-->

* Add multi-tenancy to Thanos Ruler. It's not needed. One will still be able to point their Ruler to the multi-tenant Query Frontend, effectively making it multi-tenant.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* Implement cross-tenant querying. It poses the question about how to track metrics of a multi-tenant query, probably requiring new logic for query splitting and/or separation of the concepts of query initiator tenant and query target tenants. To exemplify: if tenant A executes a query touching their own data and tenant B data (imagine a label matcher `tenant_id=~"A|B"`), how does Thanos export a request duration metric about this query? This is out of scope and an specific proposal can be created for it.
Copy link
Member

Choose a reason for hiding this comment

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

Interesting. I would argue we might need to be careful with adding feature that will block important features like cross tenancy in future. However I feel we get into the point where we talk about different tenancy aspects:

One is tenancy of data, so who owns what. Second is tenancy of query, who should be billed for query. Those write/read tenancy does not need to be 1:1. For example cross tenancy to me means that tenant A can read data of tenant B, but the quotas, settings and billing should be on behalf of one tenant.

All of this to me means we could refine this cross tenancy point. I think cross-tenancy is a goal, just we don't want shared tenancy for reads (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cross-tenancy is definitely a future goal of the project and a good "follow up", but I didn't plan this proposal to go deep into its details. I don't think it'll block in any way a cross-tenant query implementation. Cross-tenant queries will require changes to the logic behind the label enforcement part, but there's no architectural decision that will need to be undone when the time comes.

Totally we will need to develop more on these two aspects of tenancy you mention, @bwplotka. Plus we will need some configuration that will work kinda like an authorization for cross-tenant query (i.e. tenant A can query B and C; tenant B can only query C, etc).

Copy link
Member

Choose a reason for hiding this comment

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

So, it won't be possible to query data from multiple tenants anymore? 😢

Copy link
Contributor Author

@douglascamata douglascamata May 4, 2023

Choose a reason for hiding this comment

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

@GiedriusS: it will still be possible, by default, to keep backwards compatibility. When the tenancy-enforcement feature is turned on on a Querier, then it won't be possible for requests arriving there. But you can have another set of Queriers with the feature disabled and multi-tenant queries will work, just like today. o/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@GiedriusS: I am trying to ensure we keep backwards compatibility and the possibility of running queries with and without tenant-enforcement in a cluster. Maybe we can collaborate later on a proposal for multi-tenant query with the tenancy enforcement on? It's not a goal of this proposal to outline how this would work. What do you think? :D


## How

<!--
Explain the full overview of the proposed solution. Some guidelines:

* Make it concise and **simple**; put diagrams; be concrete, avoid using “really”, “amazing” and “great” (:
* How you will test and verify?
* How you will migrate users, without downtime. How we solve incompatibilities?
* What open questions are left? (“Known unknowns”)
-->

* Implement a mechanism to allow incoming requests to specify the tenant being queried using an HTTP header. This applies to all components in the query path. We follow the example of Thanos Receive, which uses the `--receive.tenant-header="THANOS-TENANT"` flag to configure the tenant header, adapting its name to each component.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* The tenant header value from a given request should travel downstream to all the components being called, so that it can be added to their metrics, traces, and logs without requiring duplicated/extra work to re-parse the query. This also applies to gRPC calls.
Copy link
Member

Choose a reason for hiding this comment

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

To be strict for gRPC - will we pass that tenant as metadata or HTTP2 header? I think the metadata is the answer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, @bwplotka. GRPC metadata seems to be the answer for it. Will batch this into updates to the proposal for the next push.

* Implement a command line argument in the Querier component that will indicate with label name that should be used to enforce tenancy. Again, we follow the example of Thanos Receive, which uses the `--receive.tenant-label-name="tenant_id"` flag to achieve this, and adapt its name. The default behavior, when the flag as an empty string as value, is to not identify tenants.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* The label verification and enforcement should be done by reusing prom-label-proxy's [Enforce.EnforceMatchers](https://github.com/prometheus-community/prom-label-proxy/blob/main/injectproxy/enforce.go#L141). There's no reason to (re)implement something specific and special for Thanos.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* This behavior should be implemented as part of the base logic of both the HTTP and gRPC query APIs, before the query is handed to the query engine. This allows users managing complex Querier trees can choose where they want this logic to be enabled.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
* Update metrics exported by the components in the query path to include the tenant label when it's available.
* Implement a tenant selector in the Query Frontend UI, which should communicate the tenant to Query Frontend using the HTTP header.
douglascamata marked this conversation as resolved.
Show resolved Hide resolved

<figure>
<img height="50%" src="../img/query-path-tenancy-proposal-diagram.svg" width="50%"/>
douglascamata marked this conversation as resolved.
Show resolved Hide resolved
<figcaption>Diagram also available <a href="https://excalidraw.com/#json=ozCXvw8LBURpWkmiA4Loq,Nclh-Sw9g_mzO3gsM6yaRQ">online</a>.</figcaption>
</figure>

## Alternatives

<!--
The section stating potential alternatives. Highlight the objections reader should have towards your proposal as they read it. Tell them why you still think you should take this path [[ref](https://twitter.com/whereistanya/status/1353853753439490049)]

1. This is why not solution Z...
-->

### Alternative implementations

1. Apply verification and enforcement logic in the Query Frontend instead of Querier.

The Query Frontend is an optional component on any Thanos deployment, while the Querier is always present. Plus, there might be deployments with multiple Querier layers where one or more might need to apply tenant verification and enforcement. On top of this, doing it in the Querier supports future work on using the [new Thanos PromQL engine](https://github.com/thanos-community/promql-engine), which can potentially make the Query Frontend unnecessary.

### Alternative solutions

1. Use a proxy to enforce and identify tenants in queries.

While this could work for some of the features, like exporting per-tenant metrics, it would have to be inserted in front of many different components. Meanwhile, it doesn't solve the requirement for per-tenant configuration.

2. Use a separate query path for each tenant.

This incurs in a lot of wasted resources and demands manual work, unless a central tenant configuration is used and a controller is built around it to automatically manage the query paths.

## Action Plan
douglascamata marked this conversation as resolved.
Show resolved Hide resolved

<!--
The tasks to do in order to migrate to the new idea.

* [ ] Task one <gh issue="">

* [ ] Task two <gh issue=""> ...
-->