Skip to content

Support for multiple weighted clusters in routing#361

Merged
mattklein123 merged 14 commits intoenvoyproxy:masterfrom
amalgam8:weighted_clusters
Jan 24, 2017
Merged

Support for multiple weighted clusters in routing#361
mattklein123 merged 14 commits intoenvoyproxy:masterfrom
amalgam8:weighted_clusters

Conversation

@rshriram
Copy link
Copy Markdown
Member

@rshriram rshriram commented Jan 20, 2017

[apologies for the delayed turn around for this feature].

This PR provides an intuitive way of specifying cluster weights, when a particular route is backed by two or more clusters. Instead of using the existing Runtime style probability specification, users can group related clusters under a single weighted_clusters block with % weights assigned to each cluster.

Please refer to #247 for more details.

The current PR is missing documentation. Will add that in a day or so. TLDR:
In the routing config, you can have either the cluster key or the weighted_clusters key.
The weighted_clusters is of the following format:

"weighted_clusters" : {
"runtime_key_prefix" : "foo",
"clusters" : [{ "name" : "cluster-name", "weight" : N },
...
]}

where N is an integer from 0 to 100. It determines the proportion of request traffic to be sent to the target cluster. The sum of all weights in the weighted cluster should be equal to 100.

On runtime support for weighted clusters: If we wish to validate the weights provided by the user (as we do it currently), it is not exactly clear how the weights would be validated (i.e. sum of weights == 100) if runtime support were to be enabled for a weighted cluster. My current inclination is to skip runtime support altogether for weighted_clusters. With the addition of RDS, a user can combine weighted cluster and RDS to dynamically change weights. It may not occur instantaneously (as it depends on the RDS poll interval).

Fixes #247

@mattklein123 @ccaraman

p.s.: For reviewing this PR, please do not look at the individual commits. Instead, I suggest looking at config_impl.h|cc as one change set and then config_impl_test.cc as another change set.

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

re: runtime, I think it wouldn't be too hard to add (we could just do it inline and abort runtime processing if the values are wrong, but I think it's OK to ignore this for now. We can do it in a follow up if we need it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no point in having this method (the base matches method) return a Route*. Just have it return bool like it used to (and change method name to something else so it's not an override).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please, fix: static const uint64_t max_weight

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should be unique_ptr. I just looked and I'm not sure why RouteEntryImplBasePtr is a shared_ptr currently. Switch that to unique_ptr also.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please fix per above.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

move comment into header file or into function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unique_ptr, newline before this line

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: please use normal layout of organizing overrides under a comment of the class they override, with any non-override methods at the top.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: please wrap comments at 100 col length.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: still needs comment wrapping fix

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should never happen, return nullptr.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should never happen, return this.

@rshriram rshriram changed the title [WIP] Support for multiple weighted clusters in routing Support for multiple weighted clusters in routing Jan 21, 2017
@rshriram
Copy link
Copy Markdown
Member Author

added runtime support as well.

@mattklein123
Copy link
Copy Markdown
Member

@rshriram: @ccaraman will review first. I will take final pass once she is done.

*(sometimes required, string)* If the route is not a redirect (*host_redirect* and/or
*path_redirect* is specified), *cluster* must be specified and indicates which upstream cluster
the request should be forwarded to.
*(sometimes required, string)* If the route is not a redirect (i.e., *host_redirect* and/or
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: remove i.e.

priority_(ConfigUtility::parsePriority(route)) {

bool have_weighted_clusters = route.hasObject("weighted_clusters");
bool have_cluster = !cluster_name_.empty() || have_weighted_clusters;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: new line below

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

overall looks good. small small comments/nits

-----------------

Compared to the ``cluster`` field that specifies a single upstream cluster as the target
of a request, the ``weighted_clusters`` allows for specification of multiple upstream clusters
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"the weighted_clusters option..."


weight
*(required, integer)* An integer between 0-100. When a request matches the route,
choice of an upstream cluster is determined by its weight. The sum of
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"the choice"

weight
*(required, integer)* An integer between 0-100. When a request matches the route,
choice of an upstream cluster is determined by its weight. The sum of
weights across all entries in the ``clusters`` array should add up to 100.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"must add up to"


.. _config_http_conn_man_route_table_weighted_routing_probabilities:

(b) Probabilistic route selection
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is somewhat of a duplication of https://lyft.github.io/envoy/docs/configuration/http_conn_man/route_config/traffic_shifting.html can we link and/or de-dup.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

So I considered that briefly. I couldn't link/reuse that document as is, because it was targeting a 2 cluster use case. Without a 3 cluster example, pointing to that document was sort of giving the incorrect impression that you can create multiple route blocks, where the value can be distributed just like weighted clusters (e.g., 33, 33, 34).

On the other hand, moving the three cluster example to traffic_shifting didn't make sense either, because the title of the page was "traffic shifting from one version to another". IOW,
The traffic shift describes a basic simple use case (moving from one version to another). Traffic splitting describes a more generic use case (using a 3 cluster example to differentiate weights vs probabilities. It is applicable to the 2 version use case as well).

If we go down the de-dup path, we could eliminate traffic shifting, with the assumption that the 3 cluster example for probability based splitting will be sufficient to construct a 2-cluster example as well. IOW, kill traffic shift, keep traffic split. Thoughts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think I would kill traffic shifting in place of your new docs. @junr03 thoughts? You wrote the other doc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

P.S., you might just add a brief sentence or something to your doc that mentions the 2 cluster case. Whatever you think is best is fine with me.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes, thats what I was thinking. if you and @junr03 have no objection to killing the traffic shifting doc, I was thinking of changing the weighted_routing to Traffic Splitting/Shifting, and add an example of two cluster case as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It looks like that would be a bigger change. For the moment, i have linked out to the traffic shifting doc as @mattklein123 suggested


const Json::ObjectPtr weighted_clusters_json = route.getObject("weighted_clusters");

if (!weighted_clusters_json->hasObject("clusters")) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would just delete this check, we will catch this with schema (makes code simpler).

for (const RouteEntryImplBasePtr& route : routes_) {
if (route->matches(headers, random_value)) {
return route.get();
const Route* cEntry = route->matches(headers, random_value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: s/cEntry/route

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That would throw an error since route is the iteration variable in the for loop. I could rename it to something more sensible.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

sorry, just pick another name like "entry" or "route_entry"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: still needs comment wrapping fix

return loader_.snapshot().getInteger(runtime_key_, cluster_weight_);
}

static const uint64_t MAX_CLUSTER_WEIGHT;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: variable definitions go below method definitions

const std::string runtime_key_;
Runtime::Loader& loader_;
const std::string cluster_name_;
uint64_t cluster_weight_;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

const

const std::string cluster_name_;
uint64_t cluster_weight_;
};
typedef std::unique_ptr<WeightedClusterEntry> WeightedClusterEntryPtr;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: newline before this line

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

what's the convention for new lines?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't have anything typed out (sorry), and clang-format doesn't check for this. You can look at the rest of the code base which in general is very consistent. I'm sorry that this is annoying but it's important to keep things consistent and you will pick it up pretty quickly.

@rshriram
Copy link
Copy Markdown
Member Author

addressed all except the traffic shifting/splitting issue. Waiting on feedback from @junr03 .

.. _config_http_conn_man_route_table_route_cluster:

cluster
*(sometimes required, string)* If the route is not a redirect (i.e., *host_redirect* and/or
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: remove ie.

EXPECT_EQ(nullptr, config.route(headers, 0)->redirectEntry());
EXPECT_EQ("www2", config.route(headers, 0)->routeEntry()->clusterName());
}
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: new line

}
}

TEST(RouteMatcherTest, WeightedClusters) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: Please add a test where random value is greater than 100.

@junr03
Copy link
Copy Markdown
Member

junr03 commented Jan 24, 2017

@rshriram after reading your doc it is obvious to me how you could do traffic shifting with the same mechanism, so I agree that having both docs is somewhat duplication. However, I think that it is better to have a traffic shifting example to make the use case explicit for users. I think it would be best to merge the two docs, eliminating duplicate info from the traffic shifting doc as needed.

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

looks great. thank you for all the fixes/changes.

@mattklein123 mattklein123 merged commit 2debf05 into envoyproxy:master Jan 24, 2017
@rshriram
Copy link
Copy Markdown
Member Author

@junr03 I will send a separate PR to merge the two docs.

@junr03
Copy link
Copy Markdown
Member

junr03 commented Jan 25, 2017

great!

@mattklein123
Copy link
Copy Markdown
Member

@rshriram @junr03 sorry I thought this was done. A follow up docs PR sounds good.

@rshriram rshriram deleted the weighted_clusters branch January 30, 2017 02:38
rshriram pushed a commit to rshriram/envoy that referenced this pull request Oct 30, 2018
* Removed pending requests management

* Exposed ConfigLoadingStatus

* Added description of the config loading status
rshriram pushed a commit to rshriram/envoy that referenced this pull request Oct 30, 2018
Automatic merge from submit-queue.

[DO NOT MERGE] Auto PR to update dependencies of mixerclient

This PR will be merged automatically once checks are successful.
```release-note
none
```
jplevyak pushed a commit to jplevyak/envoy that referenced this pull request Jan 22, 2020
Signed-off-by: Kuat Yessenov <kuat@google.com>
mathetake pushed a commit that referenced this pull request Mar 3, 2026
**Commit Message**

This adds timeouts field on AIServiceBackend to allow the configuration
of timeouts per backend.

**Related Issues/PRs (if applicable)**

Fixes #361

---------

Signed-off-by: Loong <long0dai@foxmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

multi-cluster weighted routing rule

4 participants