From ba2fab07e3b376d515b5728a145c9170f2dbd838 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Thu, 9 Nov 2023 19:32:41 +0000 Subject: [PATCH 1/5] Revert "fix: only enable full scan when enable_full_scan is set explicitly forleast request lb (#30794)" This reverts commit e93e55643d7bbe7766741f35ac79a0b2083a39cb. Revert "Fix least request lb not fair (#29873)" This reverts commit 3ea2bc40590c1a48f26e8297ae55d7a6d08083e9. restore api Signed-off-by: Kuat Yessenov fix merge Signed-off-by: Kuat Yessenov --- .../least_request/v3/least_request.proto | 1 + changelogs/current.yaml | 13 ----- .../load_balancing/load_balancers.rst | 4 +- source/common/upstream/load_balancer_impl.cc | 18 ------- source/common/upstream/load_balancer_impl.h | 5 +- .../upstream/load_balancer_impl_test.cc | 49 ------------------- 6 files changed, 3 insertions(+), 87 deletions(-) diff --git a/api/envoy/extensions/load_balancing_policies/least_request/v3/least_request.proto b/api/envoy/extensions/load_balancing_policies/least_request/v3/least_request.proto index 7be284a4c6090..ebef61852e215 100644 --- a/api/envoy/extensions/load_balancing_policies/least_request/v3/least_request.proto +++ b/api/envoy/extensions/load_balancing_policies/least_request/v3/least_request.proto @@ -60,6 +60,7 @@ message LeastRequest { // Configuration for local zone aware load balancing or locality weighted load balancing. common.v3.LocalityLbConfig locality_lb_config = 4; + // [#not-implemented-hide:] // Configuration for performing full scan on the list of hosts. // If this configuration is set, when selecting the host a full scan on the list hosts will be // used to select the one with least requests instead of using random choices. diff --git a/changelogs/current.yaml b/changelogs/current.yaml index 6b52de8ee5a67..03cd7758d6f7d 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -25,12 +25,6 @@ minor_behavior_changes: change: | uses http async client to fetch the credentials from EC2 instance metadata and ECS task metadata providers instead of libcurl which is deprecated. To revert this behavior set ``envoy.reloadable_features.use_libcurl_to_fetch_aws_credentials`` to true. -- area: upstream - change: | - Fixed a reported issue (https://github.com/envoyproxy/envoy/issues/11004) that causes the Least - Request load balancer policy to be unfair when the number of hosts are very small, when the number - of hosts is smaller than the choice_count, instead of randomly selection hosts from the list, we - perform a full scan on it to choose the host with least requests. - area: local_rate_limit change: | Added new configuration field :ref:`rate_limited_as_resource_exhausted @@ -112,13 +106,6 @@ new_features: change: | Added :ref:`the Basic Auth filter `, which can be used to authenticate user credentials in the HTTP Authentication heaer defined in `RFC7617 `_. -- area: upstream - change: | - Added :ref:`enable_full_scan ` - option to the least requested load balancer. If set to true, Envoy will perform a full scan on the list of hosts - instead of using :ref:`choice_count - ` - to select the hosts. - area: stats change: | added :ref:`per_endpoint_stats ` to get some metrics diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst index f6deaa4968a83..e99fe65b231ca 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst @@ -38,9 +38,7 @@ same or different weights. approach is nearly as good as an O(N) full scan). This is also known as P2C (power of two choices). The P2C load balancer has the property that a host with the highest number of active requests in the cluster will never receive new requests. It will be allowed to drain until it is - less than or equal to all of the other hosts. The number of hosts chosen can be changed by setting - ``choice_count``. - + less than or equal to all of the other hosts. * *all weights not equal*: If two or more hosts in the cluster have different load balancing weights, the load balancer shifts into a mode where it uses a weighted round robin schedule in which weights are dynamically adjusted based on the host's request load at the time of selection. diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index bfcc451981d96..c85565bfc6fca 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -1299,24 +1299,6 @@ HostConstSharedPtr LeastRequestLoadBalancer::unweightedHostPick(const HostVector const HostsSource&) { HostSharedPtr candidate_host = nullptr; - // Do full scan if it's required explicitly. - if (enable_full_scan_) { - for (const auto& sampled_host : hosts_to_use) { - if (candidate_host == nullptr) { - // Make a first choice to start the comparisons. - candidate_host = sampled_host; - continue; - } - - const auto candidate_active_rq = candidate_host->stats().rq_active_.value(); - const auto sampled_active_rq = sampled_host->stats().rq_active_.value(); - if (sampled_active_rq < candidate_active_rq) { - candidate_host = sampled_host; - } - } - return candidate_host; - } - for (uint32_t choice_idx = 0; choice_idx < choice_count_; ++choice_idx) { const int rand_idx = random_.random() % hosts_to_use.size(); const HostSharedPtr& sampled_host = hosts_to_use[rand_idx]; diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index c5eeed3916db8..614541057798c 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -710,9 +710,7 @@ class LeastRequestLoadBalancer : public EdfLoadBalancerBase { least_request_config.has_active_request_bias() ? absl::optional( {least_request_config.active_request_bias(), runtime}) - : absl::nullopt), - enable_full_scan_( - PROTOBUF_GET_WRAPPED_OR_DEFAULT(least_request_config, enable_full_scan, false)) { + : absl::nullopt) { initialize(); } @@ -748,7 +746,6 @@ class LeastRequestLoadBalancer : public EdfLoadBalancerBase { double active_request_bias_{}; const absl::optional active_request_bias_runtime_; - const bool enable_full_scan_{}; }; /** diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index 379f6b082b189..518f2a4de1d00 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -2880,55 +2880,6 @@ TEST_P(LeastRequestLoadBalancerTest, PNC) { EXPECT_EQ(hostSet().healthy_hosts_[3], lb_5.chooseHost(nullptr)); } -TEST_P(LeastRequestLoadBalancerTest, FullScan) { - hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime()), - makeTestHost(info_, "tcp://127.0.0.1:81", simTime()), - makeTestHost(info_, "tcp://127.0.0.1:82", simTime()), - makeTestHost(info_, "tcp://127.0.0.1:83", simTime()), - makeTestHost(info_, "tcp://127.0.0.1:84", simTime())}; - hostSet().hosts_ = hostSet().healthy_hosts_; - hostSet().runCallbacks({}, {}); // Trigger callbacks. The added/removed lists are not relevant. - - hostSet().healthy_hosts_[0]->stats().rq_active_.set(4); - hostSet().healthy_hosts_[1]->stats().rq_active_.set(3); - hostSet().healthy_hosts_[2]->stats().rq_active_.set(2); - hostSet().healthy_hosts_[3]->stats().rq_active_.set(1); - hostSet().healthy_hosts_[4]->stats().rq_active_.set(5); - - // Creating various load balancer objects with different choice configs. - envoy::extensions::load_balancing_policies::least_request::v3::LeastRequest lr_lb_config; - lr_lb_config.mutable_choice_count()->set_value(2); - // Enable full table scan on hosts - lr_lb_config.mutable_enable_full_scan()->set_value(true); - common_config_.mutable_healthy_panic_threshold()->set_value(0); - - LeastRequestLoadBalancer lb_2{priority_set_, nullptr, stats_, runtime_, - random_, 1, lr_lb_config, simTime()}; - lr_lb_config.mutable_choice_count()->set_value(3); - LeastRequestLoadBalancer lb_3{priority_set_, nullptr, stats_, runtime_, - random_, 1, lr_lb_config, simTime()}; - lr_lb_config.mutable_choice_count()->set_value(4); - LeastRequestLoadBalancer lb_4{priority_set_, nullptr, stats_, runtime_, - random_, 1, lr_lb_config, simTime()}; - lr_lb_config.mutable_choice_count()->set_value(6); - LeastRequestLoadBalancer lb_6{priority_set_, nullptr, stats_, runtime_, - random_, 1, lr_lb_config, simTime()}; - - // random is called only once every time and is not to select the host. - - EXPECT_CALL(random_, random()).WillOnce(Return(9999)); - EXPECT_EQ(hostSet().healthy_hosts_[3], lb_2.chooseHost(nullptr)); - - EXPECT_CALL(random_, random()).WillOnce(Return(9999)); - EXPECT_EQ(hostSet().healthy_hosts_[3], lb_3.chooseHost(nullptr)); - - EXPECT_CALL(random_, random()).WillOnce(Return(9999)); - EXPECT_EQ(hostSet().healthy_hosts_[3], lb_4.chooseHost(nullptr)); - - EXPECT_CALL(random_, random()).WillOnce(Return(9999)); - EXPECT_EQ(hostSet().healthy_hosts_[3], lb_6.chooseHost(nullptr)); -} - TEST_P(LeastRequestLoadBalancerTest, WeightImbalance) { hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime(), 1), makeTestHost(info_, "tcp://127.0.0.1:81", simTime(), 2)}; From 82c1d783448406e111dc4776f58c3111cf12cc60 Mon Sep 17 00:00:00 2001 From: Tony Allen Date: Fri, 10 Nov 2023 00:22:32 +0000 Subject: [PATCH 2/5] test: Add a LB simulation test to validate selection probabilities Signed-off-by: Tony Allen --- .../load_balancing/load_balancers.rst | 5 +- .../upstream/load_balancer_simulation_test.cc | 142 +++++++++++++++--- 2 files changed, 120 insertions(+), 27 deletions(-) diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst index e99fe65b231ca..e4d23bc644175 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst @@ -36,9 +36,8 @@ same or different weights. host which has the fewest active requests (`Mitzenmacher et al. `_ has shown that this approach is nearly as good as an O(N) full scan). This is also known as P2C (power of two - choices). The P2C load balancer has the property that a host with the highest number of active - requests in the cluster will never receive new requests. It will be allowed to drain until it is - less than or equal to all of the other hosts. + choices). In P2C selection is also particularly useful for load balancer implementations due to + its resistance to herding behavior. * *all weights not equal*: If two or more hosts in the cluster have different load balancing weights, the load balancer shifts into a mode where it uses a weighted round robin schedule in which weights are dynamically adjusted based on the host's request load at the time of selection. diff --git a/test/common/upstream/load_balancer_simulation_test.cc b/test/common/upstream/load_balancer_simulation_test.cc index 22c1f175b44dc..b5582616b7006 100644 --- a/test/common/upstream/load_balancer_simulation_test.cc +++ b/test/common/upstream/load_balancer_simulation_test.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -41,27 +42,58 @@ static HostSharedPtr newTestHost(Upstream::ClusterInfoConstSharedPtr cluster, envoy::config::core::v3::UNKNOWN, time_source)}; } -// Simulate weighted LR load balancer. -TEST(DISABLED_LeastRequestLoadBalancerWeightTest, Weight) { - const uint64_t num_hosts = 4; - const uint64_t weighted_subset_percent = 50; - const uint64_t weight = 2; // weighted_subset_percent of hosts will have this weight. - const uint64_t active_requests = 3; // weighted_subset_percent will have this active requests. +// Defines parameters for LeastRequestLoadBalancerWeightTest cases. +struct LRLBTestParams { + // The total number of hosts. + uint64_t num_hosts; + + // Number of hosts that are part of the subset. + uint64_t num_subset_hosts; + + // The weight assigned to each subset host. + uint64_t weight; + + // The number of active requests each subset host will be loaded with. + uint64_t active_request_count; + + // An unordered collection of expected selection probabilities for the hosts. The test will simply + // sort the expected and observed selection probabilities and verify each element is within some + // expected tolerance. Therefore, the vector does not need to be sorted. + std::vector expected_selection_probs; + + // Observed selection probabilities must be within tolerance_pct of the expected to pass the test. + // The expected range is [0,100). + double tolerance_pct; +}; + +void leastRequestLBWeightTest(LRLBTestParams params) { + constexpr uint64_t n = 100000; + + // Validate params. + ASSERT_GT(params.num_hosts, 0); + ASSERT_LE(params.num_subset_hosts, params.num_hosts); + ASSERT_GT(params.weight, 0); + ASSERT_EQ(params.expected_selection_probs.size(), params.num_hosts); + ASSERT_LT(params.tolerance_pct, 100); + ASSERT_GE(params.tolerance_pct, 0); - PrioritySetImpl priority_set; - std::shared_ptr info_{new NiceMock()}; NiceMock time_source_; HostVector hosts; - for (uint64_t i = 0; i < num_hosts; i++) { - const bool should_weight = i < num_hosts * (weighted_subset_percent / 100.0); - hosts.push_back(makeTestHost(info_, fmt::format("tcp://10.0.{}.{}:6379", i / 256, i % 256), - time_source_, should_weight ? weight : 1)); + absl::node_hash_map host_hits; + std::shared_ptr info{new NiceMock()}; + for (uint64_t i = 0; i < params.num_hosts; i++) { + const bool should_weight = i < params.num_subset_hosts; + auto hostPtr = makeTestHost(info, fmt::format("tcp://10.0.{}.{}:6379", i / 256, i % 256), + time_source_, should_weight ? params.weight : 1); + host_hits[hostPtr] = 0; + hosts.push_back(hostPtr); if (should_weight) { - hosts.back()->stats().rq_active_.set(active_requests); + hosts.back()->stats().rq_active_.set(params.active_request_count); } } HostVectorConstSharedPtr updated_hosts{new HostVector(hosts)}; HostsPerLocalitySharedPtr updated_locality_hosts{new HostsPerLocalityImpl(hosts)}; + PrioritySetImpl priority_set; priority_set.updateHosts( 0, updateHostsParams(updated_hosts, updated_locality_hosts, @@ -81,26 +113,88 @@ TEST(DISABLED_LeastRequestLoadBalancerWeightTest, Weight) { priority_set, nullptr, lb_stats, runtime, random, common_config, least_request_lb_config, *time_source}; - absl::node_hash_map host_hits; - const uint64_t total_requests = 100; - for (uint64_t i = 0; i < total_requests; i++) { + for (uint64_t i = 0; i < n; i++) { host_hits[lb_.chooseHost(nullptr)]++; } - absl::node_hash_map weight_to_percent; + std::vector observed_pcts; for (const auto& host : host_hits) { - std::cout << fmt::format("url:{}, weight:{}, hits:{}, percent_of_total:{}\n", - host.first->address()->asString(), host.first->weight(), host.second, - (static_cast(host.second) / total_requests) * 100); - weight_to_percent[host.first->weight()] += - (static_cast(host.second) / total_requests) * 100; + observed_pcts.push_back((static_cast(host.second) / n) * 100); } - for (const auto& weight : weight_to_percent) { - std::cout << fmt::format("weight:{}, percent:{}\n", weight.first, weight.second); + std::sort(observed_pcts.begin(), observed_pcts.end()); + std::sort(params.expected_selection_probs.begin(), params.expected_selection_probs.end()); + ASSERT_EQ(observed_pcts.size(), params.expected_selection_probs.size()); + for (uint64_t i = 0; i < observed_pcts.size(); i++) { + EXPECT_NEAR(params.expected_selection_probs[i], observed_pcts[i], params.tolerance_pct); } } +// Simulate weighted LR load balancer and verify expected selection probabilities. +TEST(LeastRequestLoadBalancerWeightTest, Weight) { + LRLBTestParams params; + + // No active requests or weight differences. This should look like uniform random LB. + params.num_hosts = 3; + params.num_subset_hosts = 1; + params.active_request_count = 0; + params.expected_selection_probs = {33.333, 33.333, 33.333}; + params.weight = 1; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); + + // Single host (out of 3) with lots of in-flight requests. Given that P2C will choose 2 hosts and + // take the one with higher weight, the only circumstance that the host with many in-flight + // requests will be picked is if P2C selects it twice. + params.num_hosts = 3; + params.num_subset_hosts = 1; + params.active_request_count = 10; + params.expected_selection_probs = {44.45, 44.45, 11.1}; + params.weight = 1; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); + + // Same as above, but with 2 hosts. The busy host will only be chosen if P2C picks it for both + // selections. + params.num_hosts = 2; + params.num_subset_hosts = 1; + params.active_request_count = 10; + params.expected_selection_probs = {25, 75}; + params.weight = 1; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); + + // Heterogeneous weights with no active requests. This should behave identically to weighted + // round-robin. + params.num_hosts = 2; + params.num_subset_hosts = 1; + params.active_request_count = 0; + params.expected_selection_probs = {66.66, 33.33}; + params.weight = 2; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); + + // Same as above, but we'll scale the subset's weight with active requests. With a default + // active_request_bias of 1.0, the subset host with a single active request will be cut in half, + // making both hosts have an identical weight. + params.num_hosts = 2; + params.num_subset_hosts = 1; + params.active_request_count = 1; + params.expected_selection_probs = {50, 50}; + params.weight = 2; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); + + // Same as above, but with 3 hosts. + params.num_hosts = 3; + params.num_subset_hosts = 1; + params.active_request_count = 1; + params.expected_selection_probs = {33.3, 33.3, 33.3}; + params.weight = 2; + params.tolerance_pct = 1.0; + leastRequestLBWeightTest(params); +} + /** * This test is for simulation only and should not be run as part of unit tests. */ From ea9417d1c0f574398cf3f35396a37c5b499659cc Mon Sep 17 00:00:00 2001 From: Tony Allen Date: Mon, 11 Dec 2023 18:19:00 +0000 Subject: [PATCH 3/5] . Signed-off-by: Tony Allen --- changelogs/current.yaml | 5 +++-- .../arch_overview/upstream/load_balancing/load_balancers.rst | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/changelogs/current.yaml b/changelogs/current.yaml index d979c7986620c..a6e637a8912a5 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -40,8 +40,9 @@ minor_behavior_changes: To get the protocol, please use GetProperty("request.protocol") instead. - area: aws change: | - uses http async client to fetch the credentials from EC2 instance metadata and ECS task metadata providers instead of libcurl - which is deprecated. To revert this behavior set ``envoy.reloadable_features.use_libcurl_to_fetch_aws_credentials`` to true. + Added support to use http async client to fetch the credentials from EC2 instance metadata and ECS task metadata providers + instead of libcurl which is deprecated. By default this behavior is disabled. To enable set + ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` to true. - area: local_rate_limit change: | Added new configuration field :ref:`rate_limited_as_resource_exhausted diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst index 3dc27ce82d8c3..82839e3024b2a 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst @@ -39,7 +39,6 @@ same or different weights. choices). The P2C load balancer has the property that host weights will decrease as the number of active requests on those hosts increases. P2C selection is particularly useful for load balancer implementations due to its resistance to herding behavior. - * *all weights not equal*: If two or more hosts in the cluster have different load balancing weights, the load balancer shifts into a mode where it uses a weighted round robin schedule in which weights are dynamically adjusted based on the host's request load at the time of selection. From 16d259c4ea397c951a6ec99a1270a569ea624d50 Mon Sep 17 00:00:00 2001 From: Tony Allen Date: Mon, 11 Dec 2023 21:45:37 +0000 Subject: [PATCH 4/5] comments Signed-off-by: Tony Allen --- changelogs/current.yaml | 5 ---- .../load_balancing/load_balancers.rst | 3 ++- .../upstream/load_balancer_simulation_test.cc | 26 +++++++------------ 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/changelogs/current.yaml b/changelogs/current.yaml index a6e637a8912a5..5323e6429d565 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -159,11 +159,6 @@ new_features: change: | Added :ref:`the Basic Auth filter `, which can be used to authenticate user credentials in the HTTP Authentication heaer defined in `RFC7617 `_. -- area: upstream - change: | - Added support to use http async client to fetch the credentials from EC2 instance metadata and ECS task metadata providers - instead of libcurl which is deprecated. By default this behavior is disabled. To enable set - ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` to true. - area: upstream change: | Implmented API :ref:`drop_overloads` diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst index 82839e3024b2a..103ab2e03a88d 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst @@ -38,7 +38,8 @@ same or different weights. approach is nearly as good as an O(N) full scan). This is also known as P2C (power of two choices). The P2C load balancer has the property that host weights will decrease as the number of active requests on those hosts increases. P2C selection is particularly useful for load - balancer implementations due to its resistance to herding behavior. + balancer implementations due to its resistance to + [herding behavior](https://en.wikipedia.org/wiki/Thundering_herd_problem). * *all weights not equal*: If two or more hosts in the cluster have different load balancing weights, the load balancer shifts into a mode where it uses a weighted round robin schedule in which weights are dynamically adjusted based on the host's request load at the time of selection. diff --git a/test/common/upstream/load_balancer_simulation_test.cc b/test/common/upstream/load_balancer_simulation_test.cc index b5582616b7006..1ec475438a881 100644 --- a/test/common/upstream/load_balancer_simulation_test.cc +++ b/test/common/upstream/load_balancer_simulation_test.cc @@ -60,22 +60,22 @@ struct LRLBTestParams { // sort the expected and observed selection probabilities and verify each element is within some // expected tolerance. Therefore, the vector does not need to be sorted. std::vector expected_selection_probs; - - // Observed selection probabilities must be within tolerance_pct of the expected to pass the test. - // The expected range is [0,100). - double tolerance_pct; }; void leastRequestLBWeightTest(LRLBTestParams params) { - constexpr uint64_t n = 100000; + constexpr uint64_t num_requests = 100000; + + // Observed selection probabilities must be within tolerance_pct of the expected to pass the test. + // The expected range is [0,100). + constexpr double tolerance_pct = 1.0; // Validate params. ASSERT_GT(params.num_hosts, 0); ASSERT_LE(params.num_subset_hosts, params.num_hosts); ASSERT_GT(params.weight, 0); ASSERT_EQ(params.expected_selection_probs.size(), params.num_hosts); - ASSERT_LT(params.tolerance_pct, 100); - ASSERT_GE(params.tolerance_pct, 0); + ASSERT_LT(tolerance_pct, 100); + ASSERT_GE(tolerance_pct, 0); NiceMock time_source_; HostVector hosts; @@ -113,20 +113,20 @@ void leastRequestLBWeightTest(LRLBTestParams params) { priority_set, nullptr, lb_stats, runtime, random, common_config, least_request_lb_config, *time_source}; - for (uint64_t i = 0; i < n; i++) { + for (uint64_t i = 0; i < num_requests; i++) { host_hits[lb_.chooseHost(nullptr)]++; } std::vector observed_pcts; for (const auto& host : host_hits) { - observed_pcts.push_back((static_cast(host.second) / n) * 100); + observed_pcts.push_back((static_cast(host.second) / num_requests) * 100); } std::sort(observed_pcts.begin(), observed_pcts.end()); std::sort(params.expected_selection_probs.begin(), params.expected_selection_probs.end()); ASSERT_EQ(observed_pcts.size(), params.expected_selection_probs.size()); for (uint64_t i = 0; i < observed_pcts.size(); i++) { - EXPECT_NEAR(params.expected_selection_probs[i], observed_pcts[i], params.tolerance_pct); + EXPECT_NEAR(params.expected_selection_probs[i], observed_pcts[i], tolerance_pct); } } @@ -140,7 +140,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 0; params.expected_selection_probs = {33.333, 33.333, 33.333}; params.weight = 1; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); // Single host (out of 3) with lots of in-flight requests. Given that P2C will choose 2 hosts and @@ -151,7 +150,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 10; params.expected_selection_probs = {44.45, 44.45, 11.1}; params.weight = 1; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); // Same as above, but with 2 hosts. The busy host will only be chosen if P2C picks it for both @@ -161,7 +159,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 10; params.expected_selection_probs = {25, 75}; params.weight = 1; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); // Heterogeneous weights with no active requests. This should behave identically to weighted @@ -171,7 +168,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 0; params.expected_selection_probs = {66.66, 33.33}; params.weight = 2; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); // Same as above, but we'll scale the subset's weight with active requests. With a default @@ -182,7 +178,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 1; params.expected_selection_probs = {50, 50}; params.weight = 2; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); // Same as above, but with 3 hosts. @@ -191,7 +186,6 @@ TEST(LeastRequestLoadBalancerWeightTest, Weight) { params.active_request_count = 1; params.expected_selection_probs = {33.3, 33.3, 33.3}; params.weight = 2; - params.tolerance_pct = 1.0; leastRequestLBWeightTest(params); } From 400af7f69038c0bcdf38d8284a8a307634d17996 Mon Sep 17 00:00:00 2001 From: Tony Allen Date: Tue, 12 Dec 2023 18:22:53 +0000 Subject: [PATCH 5/5] format Signed-off-by: Tony Allen --- .../arch_overview/upstream/load_balancing/load_balancers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst index 103ab2e03a88d..3dac22ac4519d 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/load_balancers.rst @@ -38,7 +38,7 @@ same or different weights. approach is nearly as good as an O(N) full scan). This is also known as P2C (power of two choices). The P2C load balancer has the property that host weights will decrease as the number of active requests on those hosts increases. P2C selection is particularly useful for load - balancer implementations due to its resistance to + balancer implementations due to its resistance to [herding behavior](https://en.wikipedia.org/wiki/Thundering_herd_problem). * *all weights not equal*: If two or more hosts in the cluster have different load balancing weights, the load balancer shifts into a mode where it uses a weighted round robin schedule in