-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Introduce Least Request LB active request bias config #11252
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
Changes from 1 commit
a1b52fd
762e61b
4cf5f19
0a2b1fc
6f9b89c
6864b50
25f7c98
f4b2da3
e96d52d
a5d7782
cfca8f7
ce291d6
b487a5e
d7cf64c
3fc99ea
9be22f0
f2d8924
71fcad8
2690778
be7c000
a4e7b39
1010883
a6a285d
2676928
100c3db
cf06a76
eb1b857
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| #include "envoy/upstream/upstream.h" | ||
|
|
||
| #include "common/protobuf/utility.h" | ||
| #include "common/runtime/runtime_features.h" | ||
| #include "common/upstream/edf_scheduler.h" | ||
|
|
||
| namespace Envoy { | ||
|
|
@@ -367,6 +368,8 @@ class EdfLoadBalancerBase : public ZoneAwareLoadBalancerBase { | |
|
|
||
| void initialize(); | ||
|
|
||
| virtual void refresh(uint32_t priority); | ||
|
|
||
| // Seed to allow us to desynchronize load balancers across a fleet. If we don't | ||
| // do this, multiple Envoys that receive an update at the same time (or even | ||
| // multiple load balancers on the same host) will send requests to | ||
|
|
@@ -375,7 +378,6 @@ class EdfLoadBalancerBase : public ZoneAwareLoadBalancerBase { | |
| const uint64_t seed_; | ||
|
|
||
| private: | ||
| void refresh(uint32_t priority); | ||
| virtual void refreshHostSource(const HostsSource& source) PURE; | ||
| virtual double hostWeight(const Host& host) PURE; | ||
| virtual HostConstSharedPtr unweightedHostPick(const HostVector& hosts_to_use, | ||
|
|
@@ -454,9 +456,25 @@ class LeastRequestLoadBalancer : public EdfLoadBalancerBase { | |
| initialize(); | ||
| } | ||
|
|
||
| HostConstSharedPtr chooseHost(LoadBalancerContext* context) override { | ||
| alternativeWeights_ = Runtime::runtimeFeatureEnabled( | ||
| "envoy.reloadable_features.alternative_least_request_weights"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For perf reasons I would not re-snap this on every choice. I would just do it in refresh below. I think this is fine. |
||
| return EdfLoadBalancerBase::chooseHost(context); | ||
| } | ||
|
|
||
| void refresh(uint32_t priority) override { | ||
| alternativeWeights_ = Runtime::runtimeFeatureEnabled( | ||
| "envoy.reloadable_features.alternative_least_request_weights"); | ||
| EdfLoadBalancerBase::refresh(priority); | ||
| } | ||
|
|
||
| private: | ||
| void refreshHostSource(const HostsSource&) override {} | ||
| double hostWeight(const Host& host) override { | ||
| if (alternativeWeights_) { | ||
| return host.weight(); | ||
| } | ||
|
|
||
| // Here we scale host weight by the number of active requests at the time we do the pick. We | ||
| // always add 1 to avoid division by 0. It might be possible to do better by picking two hosts | ||
| // off of the schedule, and selecting the one with fewer active requests at the time of | ||
|
|
@@ -469,7 +487,9 @@ class LeastRequestLoadBalancer : public EdfLoadBalancerBase { | |
| } | ||
| HostConstSharedPtr unweightedHostPick(const HostVector& hosts_to_use, | ||
| const HostsSource& source) override; | ||
|
|
||
| const uint32_t choice_count_; | ||
| bool alternativeWeights_; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. alternative_weights_
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also explain what this means exactly in a comment. It's non-obvious from the name. |
||
| }; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ | |
| #include "test/common/upstream/utility.h" | ||
| #include "test/mocks/runtime/mocks.h" | ||
| #include "test/mocks/upstream/mocks.h" | ||
| #include "test/test_common/test_runtime.h" | ||
|
|
||
| #include "gmock/gmock.h" | ||
| #include "gtest/gtest.h" | ||
|
|
@@ -1532,6 +1533,30 @@ TEST_P(LeastRequestLoadBalancerTest, WeightImbalance) { | |
| EXPECT_EQ(hostSet().healthy_hosts_[0], lb_.chooseHost(nullptr)); | ||
| } | ||
|
|
||
| TEST_P(LeastRequestLoadBalancerTest, WeightImbalanceWithAlternativeWeights) { | ||
| auto scoped_runtime = std::make_unique<TestScopedRuntime>(); | ||
| Runtime::LoaderSingleton::getExisting()->mergeValues( | ||
| {{"envoy.reloadable_features.alternative_least_request_weights", "true"}}); | ||
|
|
||
| hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", 1), | ||
| makeTestHost(info_, "tcp://127.0.0.1:81", 2)}; | ||
| stats_.max_host_weight_.set(2UL); | ||
|
|
||
| hostSet().hosts_ = hostSet().healthy_hosts_; | ||
| hostSet().runCallbacks({}, {}); // Trigger callbacks. The added/removed lists are not relevant. | ||
|
|
||
| EXPECT_CALL(random_, random()).WillRepeatedly(Return(0)); | ||
|
|
||
| // We should see 2:1 ratio for hosts[1] to hosts[0], regardless of the active request count. | ||
| hostSet().healthy_hosts_[1]->stats().rq_active_.set(1); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised this works. Are the stats affecting the outstanding requests perceived by the LB when the exponent is non-zero?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the active rq stat is used to calculate the effective weights when the exponent is > 0: https://github.com/envoyproxy/envoy/pull/11252/files/0a2b1fcdad5daeef1136ef7c2208f356d3fcf05f#diff-e746c5f817e7b535220c275b9dea666bR494 |
||
| EXPECT_EQ(hostSet().healthy_hosts_[1], lb_.chooseHost(nullptr)); | ||
| EXPECT_EQ(hostSet().healthy_hosts_[0], lb_.chooseHost(nullptr)); | ||
| EXPECT_EQ(hostSet().healthy_hosts_[1], lb_.chooseHost(nullptr)); | ||
| EXPECT_EQ(hostSet().healthy_hosts_[1], lb_.chooseHost(nullptr)); | ||
| EXPECT_EQ(hostSet().healthy_hosts_[0], lb_.chooseHost(nullptr)); | ||
| EXPECT_EQ(hostSet().healthy_hosts_[1], lb_.chooseHost(nullptr)); | ||
| } | ||
|
|
||
| TEST_P(LeastRequestLoadBalancerTest, WeightImbalanceCallbacks) { | ||
| hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", 1), | ||
| makeTestHost(info_, "tcp://127.0.0.1:81", 2)}; | ||
|
|
||
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 end up doing a real PR for this, it should be a real config option vs. one of these. I would just use a RuntimeFeatureFlag inside the LB config proto.