-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[WIP] router: support cluster picking via filter state and fallback #11661
Conversation
Signed-off-by: Andres Guedez <aguedez@google.com>
Signed-off-by: Andres Guedez <aguedez@google.com>
Signed-off-by: Andres Guedez <aguedez@google.com>
Signed-off-by: Andres Guedez <aguedez@google.com>
@htuch @mattklein123 Isn't this the same use-case that we planned to address via #8956? |
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 general this makes sense to me, thanks. I left some comments to discuss.
/wait
@@ -750,10 +750,49 @@ message RouteAction { | |||
ConnectConfig connect_config = 3; | |||
} | |||
|
|||
message ClusterSelector { |
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.
Within the selector, the types should be a required oneof, right?
Also, re: my comment below about fallback routing, I would suggest that we plan for this selector to eventually have other state provided such as when a cluster is valid. For example, it's current health state, etc. wdyt?
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, it should be a oneof
. I've just pushed a new commit addressing this.
Also, re: my comment below about fallback routing, I would suggest that we plan for this selector to eventually have other state provided such as when a cluster is valid. For example, it's current health state, etc. wdyt?
Yeah, this SGTM. I'll put more thought into this proto's structure with that in mind.
|
||
// A wrapper to enable repeated |ClusterSelector|s in a oneof. | ||
message ClusterSelectorRepeatedWrapper { | ||
repeated ClusterSelector cluster_selectors = 1; |
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.
min size 1?
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.
Fixed.
reserved 12, 18, 19, 16, 22, 21, 10; | ||
|
||
reserved "request_mirror_policy"; | ||
|
||
// NOTE: This oneof can be deprecated for a `repeated ClusterSelector`. |
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.
If we go with this can we just go ahead and do the deprecation? I agree this is the right path forward.
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.
SGTM.
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.
+1 on deprecating existing redundant selectors.
Signed-off-by: Andres Guedez <aguedez@google.com>
Signed-off-by: Andres Guedez <aguedez@google.com>
@@ -750,10 +750,54 @@ message RouteAction { | |||
ConnectConfig connect_config = 3; | |||
} | |||
|
|||
message ClusterSelector { |
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 think this should be [#not-implemented-hide:] until the implementation lands.
@@ -779,6 +823,11 @@ message RouteAction { | |||
// :ref:`traffic splitting <config_http_conn_man_route_table_traffic_splitting_split>` | |||
// for additional documentation. | |||
WeightedCluster weighted_clusters = 3; | |||
|
|||
// A list of selectors that will be iterated in order. If a selector is unable to return an |
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 think this should be [#not-implemented-hide:] until the implementation lands.
(validate.rules).string = {min_bytes: 1 well_known_regex: HTTP_HEADER_NAME strict: false} | ||
]; | ||
|
||
// Multiple upstream clusters can be specified for a given route. The |
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 think we need some worked examples on how fallback is going to happen with WeightedCluster
, either here or in the routing architecture docs. Basically, it needs to explain that we keep rolling the dice at each successive fallback, rather than rolling the dice once with the options filtered down by cluster liveness.
@markdroth I think there is overlap with the filter state action and #8956 (but not the generalized cluster fallback aspect). |
@htuch wrote:
Maybe it would help me to understand the overall goal here. It seems like this PR is a cross between the filter state action API we added in #8956 and the aggregate cluster functionality that allows falling back from a primary cluster to a secondary one when the primary is not reachable. Is there something else here that I'm missing? If not, why is this needed? Can't this just be accomplished through the two existing mechanisms? |
@markdroth the main thing you can't do with aggregate clusters is deal with the eventual consistency mismatch between RDS and CDS. This is not the use case of @AndresGuedez, but a simple example of this issue is how do you handle a missing cluster in RouteConfiguration while waiting for CDS to update? I think some folks have historically asked for fallback to a static cluster, this new API would allow that. |
I assume that the intent here is for the route to specify multiple clusters and the filter to choose between them based on the state of those clusters? If so, how is this different from the aggregate cluster functionality? I will also note that this problem seems like a fundamental property of the wildcard-semantic approach that Envoy uses for CDS. We don't have this problem in gRPC, because we make a CDS query for whatever clusters are specified in the RouteConfiguration. If we get an RDS update containing a new cluster name, any request for that new cluster will be queued until we get the necessary CDS (and EDS) resources. If we don't get those resources within some timeout period, then we consider the cluster to be in state TRANSIENT_FAILURE, and those requests will fail. This approach works fine and does not require any API change. |
The problem with aggregate cluster is you need to know all the constituent cluster in the aggregate cluster when delivering CDS. So, if you are late in your eventual consistent update of CDS for some new cluster, relative to RDS, it's not going to be available until the CDS update is received. Another example, closer to what @AndresGuedez wants, is the ability to pick cluster based on header, but have a fallback cluster for when the header yields a cluster that doesn't exist on the Envoy. |
The aggregate cluster definition comes as part of the CDS response, not the RDS response. If we're getting all of the clusters from the CDS response, including the aggregate cluster, doesn't that eliminate the consistency problem between CDS and RDS?
Can't this be done using the API we added in #8956? Why do we need a separate API for this? |
AFAICT, this API does appear to provide a solution to the use cases that have come up as part of this discussion thus far. The caveat is that it requires a filter, but that's not an issue for my deployment environment. It is arguably less user friendly than building the cluster picking fallback behavior directly into Envoy's core, but that's an expected tradeoff for being generic and enabling much greater flexibility. @htuch @mattklein123 I don't have the context for the other use cases that you've alluded to that could leverage the API I've proposed in this PR, so do you have a preference in approach? Are some of these use cases not well served by |
I think there are a few asks and tensions here:
Anything else I'm missing? |
@htuch I would add one thing, which you've already alluded to in several of your bullet points but that I want to state explicitly: I think we should try as much as possible to have only one way to do a given thing. For example, if we are going to add support for fallback clusters here, does that eliminate the need for the aggregate cluster functionality? |
I don't have a good understanding of how aggregate clusters are used today. If we think that aggregate clusters can fully support the fallback case that is potentially fine with me, though this API as proposed seems conceptually pretty simple and easy to use for some very common fallback cases which have been requested over and over again. |
In terms of UX, what would a Or is there a simpler way to do achieve this kind of fallback API for cluster selectors that would work with |
Which protos are expected to be specified in the My thinking is that a |
The use-case that originally motivated the The intent of the My intent for our use case was that we would put something like this inside the
I think you could do something similar for the fallback case. The "other config to tell the filter how to pick the cluster" could be a repeated list of clusters to choose from. That having been said, I would still like to understand why this use case cannot be addressed by the aggregate cluster functionality. In order for fallback to work, you need to know that there is at least one cluster that is already present in the CDS response, or else you have nothing to fall back to. If you can be sure that at least one cluster is already present in CDS, why can't that be an aggregate cluster? |
Great, this is what I was expecting/hoping.
Right, as long as the filter is provided an API to configure the
A guarantee that a cluster is configured, active and/or healthy is not required for my use case. We need to iterate cluster picking mechanisms, and if a cluster is not found, an error response would be returned to the client. I've emphasized "mechanisms" as that is a key difference with the use case you are describing; we first want to attempt e.g., |
Okay. Then maybe we should just implement the mechanism that we'll need for the
Okay, that makes sense. It is worth noting that if we did have the kind of extensible LB policy framework discussed in #5598, then you could probably do the equivalent of both However, if we are going to implement the mechanism that we need for |
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
That's fine with me. @mattklein123 @htuch WDYT? Please see my earlier comment for an example of how I would use Is this use case common enough that we should have an explicit API (i.e., something like this proposal) or is achieving the same goal via the generic API enough? |
I see some competing tensions:
|
@htuch From an API shephard perspective, I'd actually argue that the right approach is to make everything extensible and to support some common plugins to those extension points. So I would actually consider (1) to be a non-goal, and I think |
@markdroth I think making everything extensible where the capability is not lowest common denominator common functionality makes sense. The question is whether this falls into that category. |
My 2c is this comes up pretty often and we should build this into the core vs. requiring an extension to do this. One compromise I suppose would be to build the |
I'd be in favor of that approach. |
SGTM |
SG, thanks everyone. I'll follow up with a new PR based on |
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
NOTE: this is a WIP PR to get feedback on a proposed API change to
RouteAction
.This change introduces the following modifications to the routing API:
cluster_header
fails to find an active cluster, the next selector in the list will be attempted.