diff --git a/api/envoy/config/cluster/v3/cluster.proto b/api/envoy/config/cluster/v3/cluster.proto index e98414f8f2a4c..36263331ffac3 100644 --- a/api/envoy/config/cluster/v3/cluster.proto +++ b/api/envoy/config/cluster/v3/cluster.proto @@ -363,12 +363,17 @@ message Cluster { // By tuning the parameter, is possible to achieve polynomial or exponential shape of ramp-up curve. // // During slow start window, effective weight of an endpoint would be scaled with time factor and aggression: - // `new_weight = weight * time_factor ^ (1 / aggression)`, + // `new_weight = weight * max(min_weight_percent, time_factor ^ (1 / aggression))`, // where `time_factor=(time_since_start_seconds / slow_start_time_seconds)`. // // As time progresses, more and more traffic would be sent to endpoint, which is in slow start window. // Once host exits slow start, time_factor and aggression no longer affect its weight. core.v3.RuntimeDouble aggression = 2; + + // Configures the minimum percentage of origin weight that avoids too small new weight, + // which may cause endpoints in slow start mode receive no traffic in slow start window. + // If not specified, the default is 10%. + type.v3.Percent min_weight_percent = 3; } // Specific configuration for the RoundRobin load balancing policy. diff --git a/docs/root/intro/arch_overview/upstream/load_balancing/slow_start.rst b/docs/root/intro/arch_overview/upstream/load_balancing/slow_start.rst index e510f66982556..391160d3276b2 100644 --- a/docs/root/intro/arch_overview/upstream/load_balancing/slow_start.rst +++ b/docs/root/intro/arch_overview/upstream/load_balancing/slow_start.rst @@ -15,7 +15,7 @@ During slow start window, load balancing weight of a particular endpoint will be .. math:: - NewWeight = {Weight*TimeFactor}^\frac{1}{Aggression} + NewWeight = {Weight}*{max(MinWeightPercent,{TimeFactor}^\frac{1}{Aggression})} where, @@ -25,6 +25,8 @@ where, As time progresses, more and more traffic would be sent to endpoint within slow start window. +:ref:`MinWeightPercent parameter` specifies the minimum percent of origin weight to make sure the EDF scheduler has a reasonable deadline, default is 10%. + :ref:`Aggression parameter` non-linearly affects endpoint weight and represents the speed of ramp-up. By tuning aggression parameter, one could achieve polynomial or exponential speed for traffic increase. Below simulation demonstrates how various values for aggression affect traffic ramp-up: diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 51ce30b61fbaa..7b9058499681f 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -36,6 +36,7 @@ Bug Fixes * jwt_authn: fixed the crash when a CONNECT request is sent to JWT filter configured with regex match on the Host header. * tcp_proxy: fix a crash that occurs when configured for :ref:`upstream tunneling ` and the downstream connection disconnects while the the upstream connection or http/2 stream is still being established. * tls: fix a bug while matching a certificate SAN with an exact value in ``match_typed_subject_alt_names`` of a listener where wildcard ``*`` character is not the only character of the dns label. Example, ``baz*.example.net`` and ``*baz.example.net`` and ``b*z.example.net`` will match ``baz1.example.net`` and ``foobaz.example.net`` and ``buzz.example.net``, respectively. +* upstream: cluster slow start config add ``min_weight_percent`` field to avoid too big EDF deadline which cause slow start endpoints receiving no traffic, default 10%. This fix is releted to `issue#19526 `_. * upstream: fix stack overflow when a cluster with large number of idle connections is removed. * xray: fix the AWS X-Ray tracer extension to not sample the trace if ``sampled=`` keyword is not present in the header ``x-amzn-trace-id``. diff --git a/source/common/upstream/load_balancer_impl.cc b/source/common/upstream/load_balancer_impl.cc index 36c446bcc430d..a14f65087d7c6 100644 --- a/source/common/upstream/load_balancer_impl.cc +++ b/source/common/upstream/load_balancer_impl.cc @@ -789,7 +789,12 @@ EdfLoadBalancerBase::EdfLoadBalancerBase( slow_start_config.has_value() && slow_start_config.value().has_aggression() ? absl::optional({slow_start_config.value().aggression(), runtime}) : absl::nullopt), - time_source_(time_source), latest_host_added_time_(time_source_.monotonicTime()) { + time_source_(time_source), latest_host_added_time_(time_source_.monotonicTime()), + slow_start_min_weight_percent_(slow_start_config.has_value() + ? PROTOBUF_PERCENT_TO_DOUBLE_OR_DEFAULT( + slow_start_config.value(), min_weight_percent, 10) / + 100.0 + : 0.1) { // We fully recompute the schedulers for a given host set here on membership change, which is // consistent with what other LB implementations do (e.g. thread aware). // The downside of a full recompute is that time complexity is O(n * log n), @@ -987,7 +992,8 @@ double EdfLoadBalancerBase::applySlowStartFactor(double host_weight, const Host& auto time_factor = static_cast(std::max(std::chrono::milliseconds(1).count(), host_create_duration.count())) / slow_start_window_.count(); - return host_weight * applyAggressionFactor(time_factor); + return host_weight * + std::max(applyAggressionFactor(time_factor), slow_start_min_weight_percent_); } else { return host_weight; } diff --git a/source/common/upstream/load_balancer_impl.h b/source/common/upstream/load_balancer_impl.h index 78f2c200cc87e..e678a6f0a9a9c 100644 --- a/source/common/upstream/load_balancer_impl.h +++ b/source/common/upstream/load_balancer_impl.h @@ -467,6 +467,7 @@ class EdfLoadBalancerBase : public ZoneAwareLoadBalancerBase, const absl::optional aggression_runtime_; TimeSource& time_source_; MonotonicTime latest_host_added_time_; + const double slow_start_min_weight_percent_; }; /** diff --git a/test/common/upstream/load_balancer_impl_test.cc b/test/common/upstream/load_balancer_impl_test.cc index c2420c9215f2b..7074d63c6ac5d 100644 --- a/test/common/upstream/load_balancer_impl_test.cc +++ b/test/common/upstream/load_balancer_impl_test.cc @@ -44,6 +44,9 @@ class EdfLoadBalancerBasePeer { return std::chrono::time_point_cast(edf_lb.latest_host_added_time_) .time_since_epoch(); } + static double slowStartMinWeightPercent(const EdfLoadBalancerBase& edf_lb) { + return edf_lb.slow_start_min_weight_percent_; + } }; class TestZoneAwareLoadBalancer : public ZoneAwareLoadBalancerBase { @@ -1614,6 +1617,26 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartWithDefaultParams) { const auto latest_host_added_time = EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); EXPECT_EQ(std::chrono::milliseconds(0), latest_host_added_time); + const auto slow_start_min_weight_percent = + EdfLoadBalancerBasePeer::slowStartMinWeightPercent(static_cast(*lb_)); + EXPECT_DOUBLE_EQ(slow_start_min_weight_percent, 0.1); +} + +TEST_P(RoundRobinLoadBalancerTest, SlowStartWithMinWeightPercent) { + round_robin_lb_config_.mutable_slow_start_config()->mutable_min_weight_percent()->set_value(30); + init(false); + const auto slow_start_window = + EdfLoadBalancerBasePeer::slowStartWindow(static_cast(*lb_)); + EXPECT_EQ(std::chrono::milliseconds(0), slow_start_window); + const auto aggression = + EdfLoadBalancerBasePeer::aggression(static_cast(*lb_)); + EXPECT_EQ(1.0, aggression); + const auto latest_host_added_time = + EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); + EXPECT_EQ(std::chrono::milliseconds(0), latest_host_added_time); + const auto slow_start_min_weight_percent = + EdfLoadBalancerBasePeer::slowStartMinWeightPercent(static_cast(*lb_)); + EXPECT_DOUBLE_EQ(slow_start_min_weight_percent, 0.3); } TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWait) { @@ -1650,7 +1673,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWait) { EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); EXPECT_EQ(std::chrono::milliseconds(62000), latest_host_added_time_ms); - // host2 is 12 secs in slow start, the weight is scaled with time factor 12 / 60 == 0.2. + // host2 is 12 secs in slow start, the weight is scaled with time factor max(12 / 60, 0.1) = 0.2. simTime().advanceTimeWait(std::chrono::seconds(12)); // Recalculate weights. @@ -1737,7 +1760,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartWaitForPassingHC) { hostSet().runCallbacks({}, {}); // We expect 3:1 ratio, as host2 is in slow start mode, its weight is scaled with time factor - // 5 / 10 == 0.5. + // max(6/10, 0.1) = 0.6. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); @@ -1781,7 +1804,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartWithRuntimeAggression) { EXPECT_EQ(std::chrono::milliseconds(1000), latest_host_added_time_ms); // We should see 2:1:1 ratio, as hosts 2 and 3 are in slow start, their weights are scaled with - // 0.5 factor. + // max(0.5,0.1)=0.5 factor. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); @@ -1801,8 +1824,8 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartWithRuntimeAggression) { EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); EXPECT_EQ(std::chrono::milliseconds(10000), latest_host_added_time_ms); - // We should see 1:1:1:0 ratio, as host 2 and 3 weight is scaled with (9/10)^(1/1.5)=0.93 factor, - // host4 weight is 0.002. + // We should see 1:1:1:0 ratio, as host 2 and 3 weight is scaled with max((9/10)^(1/1.5),0.1)=0.93 + // factor, host4 weight is 1*max(0.002,0.1)=0.1. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); @@ -1810,7 +1833,8 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartWithRuntimeAggression) { EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[2], lb_->chooseHost(nullptr)); - // host4 is 9 seconds in slow start, it's weight is scaled with (9/10)^(1/1.5)=0.93 factor. + // host4 is 9 seconds in slow start, it's weight is scaled with max((9/10)^(1/1.5), 0.1)=0.93 + // factor. simTime().advanceTimeWait(std::chrono::seconds(9)); hostSet().runCallbacks({}, {}); @@ -1835,7 +1859,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitNonLinearAggression) { hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime())}; hostSet().hosts_ = hostSet().healthy_hosts_; simTime().advanceTimeWait(std::chrono::seconds(5)); - // Host1 is 5 secs in slow start, its weight is scaled with (0.5/60)^(1/2)=0.28 factor. + // Host1 is 5 secs in slow start, its weight is scaled with max((5/60)^(1/2), 0.1)=0.28 factor. hostSet().runCallbacks({}, {}); // Advance time, so that host1 is no longer in slow start. @@ -1848,7 +1872,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitNonLinearAggression) { hostSet().healthy_hosts_.push_back(host2); hostSet().hosts_ = hostSet().healthy_hosts_; - // host2 weight is scaled with 0.004 factor. + // host2 weight is scaled with max((0.001/60)^(1/2), 0.1)=max(0.004, 0.1)=0.1 factor. hostSet().runCallbacks(hosts_added, {}); // host2 is 6 secs in slow start. @@ -1858,7 +1882,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitNonLinearAggression) { hostSet().runCallbacks({}, {}); // We expect 3:1 ratio, as host2 is 6 secs in slow start mode and it's weight is scaled with - // pow(0.1, 0.5)==0.31 factor. + // max(pow(0.1, 0.5), 0.1)=0.31 factor. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); @@ -1871,7 +1895,7 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitNonLinearAggression) { hostSet().runCallbacks({}, {}); // We still expect 5:3 ratio, as host2 is in slow start mode and it's weight is scaled with - // pow(0.43, 0.5)==0.65 factor. + // max(pow(0.43, 0.5), 0.1)=0.65 factor. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_->chooseHost(nullptr)); @@ -1894,6 +1918,102 @@ TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitNonLinearAggression) { EXPECT_EQ(hostSet().healthy_hosts_[1], lb_->chooseHost(nullptr)); } +TEST_P(RoundRobinLoadBalancerTest, SlowStartNoWaitMinWeightPercent35) { + round_robin_lb_config_.mutable_slow_start_config()->mutable_slow_start_window()->set_seconds(60); + round_robin_lb_config_.mutable_slow_start_config()->mutable_min_weight_percent()->set_value(35); + simTime().advanceTimeWait(std::chrono::seconds(1)); + auto host1 = makeTestHost(info_, "tcp://127.0.0.1:80", simTime()); + host_set_.hosts_ = {host1}; + + init(true); + + // As no healthcheck is configured, hosts would enter slow start immediately. + HostVector empty; + HostVector hosts_added; + hosts_added.push_back(host1); + simTime().advanceTimeWait(std::chrono::seconds(5)); + hostSet().runCallbacks(hosts_added, empty); + auto latest_host_added_time_ms = + EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); + EXPECT_EQ(std::chrono::milliseconds(1000), latest_host_added_time_ms); + + // Advance time, so that host is no longer in slow start. + simTime().advanceTimeWait(std::chrono::seconds(56)); + + hosts_added.clear(); + auto host2 = makeTestHost(info_, "tcp://127.0.0.1:90", simTime()); + + hosts_added.push_back(host2); + + hostSet().healthy_hosts_ = {host1, host2}; + hostSet().hosts_ = hostSet().healthy_hosts_; + hostSet().runCallbacks(hosts_added, empty); + + latest_host_added_time_ms = + EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(*lb_)); + EXPECT_EQ(std::chrono::milliseconds(62000), latest_host_added_time_ms); + + // host2 is 12 secs in slow start, the weight is scaled with time factor max(12 / 60, 0.35) = + // 0.35. + simTime().advanceTimeWait(std::chrono::seconds(12)); + + // Recalculate weights. + hostSet().runCallbacks(empty, empty); + + // We expect 5:2 ratio, as host2 is in slow start mode and it's weight is scaled with + // 0.35 factor. + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[1,20/7] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[2,20/7] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[3,20/7] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[3,40/7] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[4,40/7] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[5,40/7] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[6,40/7] + + // host2 is 30 secs in slow start, the weight is scaled with time factor max(30 / 60, 0.35) == + // 0.5. + simTime().advanceTimeWait(std::chrono::seconds(18)); + + // Recalculate weights. + hostSet().runCallbacks(empty, empty); + + // We expect 2:1 ratio, as host2 is in slow start mode and it's weight is scaled with + // 0.5 factor. + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[1,2] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[2,2] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[2,4] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[3,4] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[4,4] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[4,6] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_->chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[5,6] + + // Advance time, so that there are no hosts in slow start. + simTime().advanceTimeWait(std::chrono::seconds(45)); + + // Recalculate weights. + hostSet().runCallbacks(empty, empty); + + // Now expect 1:1 ratio. + EXPECT_EQ(hostSet().healthy_hosts_[0], 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)); +} + class LeastRequestLoadBalancerTest : public LoadBalancerTestBase { public: LeastRequestLoadBalancer lb_{ @@ -2168,6 +2288,9 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartWithDefaultParams) { const auto latest_host_added_time = EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(lb_2)); EXPECT_EQ(std::chrono::milliseconds(0), latest_host_added_time); + const auto slow_start_min_weight_percent = + EdfLoadBalancerBasePeer::slowStartMinWeightPercent(static_cast(lb_2)); + EXPECT_DOUBLE_EQ(slow_start_min_weight_percent, 0.1); } TEST_P(LeastRequestLoadBalancerTest, SlowStartNoWait) { @@ -2183,7 +2306,7 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartNoWait) { hostSet().healthy_hosts_ = {makeTestHost(info_, "tcp://127.0.0.1:80", simTime())}; hostSet().hosts_ = hostSet().healthy_hosts_; simTime().advanceTimeWait(std::chrono::seconds(5)); - // Host1 is 5 secs in slow start, its weight is scaled with (5/60)^1=0.08 factor. + // Host1 is 5 secs in slow start, its weight is scaled with max((5/60)^1, 0.1)=0.1 factor. hostSet().runCallbacks({}, {}); auto latest_host_added_time = @@ -2205,7 +2328,7 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartNoWait) { EdfLoadBalancerBasePeer::latestHostAddedTime(static_cast(lb_2)); EXPECT_EQ(std::chrono::milliseconds(62000), latest_host_added_time); - // host2 is 20 secs in slow start, the weight is scaled with time factor 20 / 60 == 0.16. + // host2 is 20 secs in slow start, the weight is scaled with time factor max(20/60, 0.1) = 0.16. simTime().advanceTimeWait(std::chrono::seconds(10)); // Recalculate weights. @@ -2221,7 +2344,7 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartNoWait) { EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); - // host2 is 50 secs in slow start, the weight is scaled with time factor 40 / 60 == 0.66. + // host2 is 50 secs in slow start, the weight is scaled with time factor max(40/60, 0.1) = 0.66. simTime().advanceTimeWait(std::chrono::seconds(30)); // Recalculate weights. @@ -2292,22 +2415,35 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartWaitForPassingHC) { hostSet().runCallbacks({}, {}); // We expect 11:2 ratio, as host2 is in slow start mode, its weight is scaled with factor - // pow(0.1, 1.11)=0.07. Host1 is 7 seconds in slow start and its weight is scaled with active - // request and time bias 0.53 * pow(0.7, 1.11) = 0.36. - - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); + // max(pow(0.1, 1.11), 0.1)=0.1. Host1 is 7 seconds in slow start and its weight is scaled with + // active request and time bias 0.53 * max(pow(0.7, 1.11), 0.1) = 0.36. + + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[25/9, 10] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[50/9, 10] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[75/9, 10] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[100/9, 10] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[100/9, 20] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[125/9, 20] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[150/9, 20] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[175/9, 20] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[200/9, 20] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[200/9, 30] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[225/9, 30] + EXPECT_EQ(hostSet().healthy_hosts_[0], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[250/9, 30] + EXPECT_EQ(hostSet().healthy_hosts_[1], + lb_2.chooseHost(nullptr)); // before choose: edf.deadline[host1,host2]=[275/9, 30] simTime().advanceTimeWait(std::chrono::seconds(3)); host1->healthFlagSet(Host::HealthFlag::FAILED_ACTIVE_HC); @@ -2315,7 +2451,7 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartWaitForPassingHC) { hostSet().runCallbacks({}, {}); // We expect 3:5 ratio, as host2 is 4 seconds in slow start, its weight is scaled with factor - // pow(0.4, 1.11)=0.36. Host1 is not in slow start and its weight is scaled with active + // max(pow(0.4, 1.11), 0.1)=0.36. Host1 is not in slow start and its weight is scaled with active // request bias = 0.53. EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); @@ -2326,13 +2462,13 @@ TEST_P(LeastRequestLoadBalancerTest, SlowStartWaitForPassingHC) { EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); - // Host2 is 7 seconds in slow start, the weight is scaled with time factor 7 / 10 == 0.6. + // Host2 is 7 seconds in slow start, the weight is scaled with time factor 7 / 10 == 0.7. simTime().advanceTimeWait(std::chrono::seconds(3)); hostSet().runCallbacks({}, {}); // We expect 6:5 ratio, as host2 is in slow start mode, its weight is scaled with time factor - // pow(0.7, 1.11)=0.67. Host1 weight is scaled with active request bias = 0.53. + // max(pow(0.7, 1.11), 0.1)=0.67. Host1 weight is scaled with active request bias = 0.53. EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[0], lb_2.chooseHost(nullptr)); EXPECT_EQ(hostSet().healthy_hosts_[1], lb_2.chooseHost(nullptr));