Skip to content

Commit ef8f744

Browse files
altaiezioranurag.agjukiearkodg
authored
feat(loadbalancer): Add LoadBalancerType Client Side Weighted Round Robin (#7407)
* Add support for ClientSideWeightedRoundRobin load balancer policy in Gateway CRDs, ensuring configurable parameters and validation rules are integrated. Includes e2e test for validation. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Adds / Updates test cases for client wrr Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Fix: gen-check ci, coverage-check Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Remove `enableOOBLoadReport` and `oobReportingPeriod` fields from gateway CRDs and related configurations. Update associated test data and documentation. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Remove `enableOOBLoadReport` and `oobReportingPeriod` fields from ClientSideWeightedRoundRobin configuration, update affected tests and CRDs. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Change `ErrorUtilizationPenalty` type from float to integer across Gateway CRDs, configuration files, and related tests. Adjust documentation to reflect percentage-based representation. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Refactor `ErrorUtilizationPenalty` to use integer type with percentage-based representation in Gateway CRDs, configurations, and tests. Adjust related documentation and ensure backward compatibility. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Refactor: Replace `ptr.To(metav1.Duration)` with `ir.MetaV1DurationPtr` across gateway configurations and tests for cleaner and consistent duration handling. Remove unused `metav1` imports where applicable. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Add support for SlowStart configuration for ClientSideWeightedRoundRobin load balancer in Gateway CRDs, configurations, and tests. Adjust validation rules and documentation accordingly. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Replace `ClientSideWeightedRoundRobin` load balancer type with `BackendUtilization` in Gateway CRDs, configurations, and tests. Revise validation rules, documentation, and enums accordingly. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Replace `ClientSideWeightedRoundRobin` references with `BackendUtilization` in load balancing tests and documentation. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Replace `lb-backend-bu` references with `lb-backend-utilization` across tests, configurations, and load balancing policies for consistency. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Remove: Delete obsolete BackendUtilization OOB and penalty load balancing tests. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Add detailed documentation and configuration examples for Backend Utilization (ORCA) load balancing in Gateway CRDs and related docs. Refine header handling and metric formats. Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> * Update: Rename `ErrorUtilizationPenalty` to `ErrorUtilizationPenaltyPercent` across API, tests, and internal logic for clarity and precision. Adjust related documentation and validations. Signed-off-by: anurag.ag <6075379+altaiezior@users.noreply.github.com> * Update: Add support for `removeResponseHeaders` in `BackendUtilization`. Adjust logic, tests, and documentation to highlight default value and ORCA header removal. Signed-off-by: anurag.ag <6075379+altaiezior@users.noreply.github.com> * Update: Replace `removeResponseHeaders` with `keepResponseHeaders` across API, internal logic, and templates. Adjust defaults, documentation, and validations to reflect behavior change. Signed-off-by: anurag.ag <6075379+altaiezior@users.noreply.github.com> * Refactor: Reorganize import order in `cluster_test.go` for consistency. Signed-off-by: anurag.ag <6075379+altaiezior@users.noreply.github.com> * Update: Fix formatting and alignment in `load_balancing.go` and `loadbalancer_types.go` for consistency. Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> * Update: Add validation to disallow ZoneAware routing for BackendUtilization load balancers. Adjust tests to reflect the new validation rule. Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> * Update: Add error handling for invalid duration values in `BackendUtilization` fields (`BlackoutPeriod`, `WeightExpirationPeriod`, `WeightUpdatePeriod`). Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> * Refactor: Simplify nil check and assignment logic in `BackendUtilization` handling within cluster translator. Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> * Update: Add support for BackendUtilization load balancing policy in BackendTrafficPolicy. Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> --------- Signed-off-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> Signed-off-by: anurag.ag <6075379+altaiezior@users.noreply.github.com> Signed-off-by: Arko Dasgupta <arkodg@users.noreply.github.com> Signed-off-by: altaiezior <6075379+altaiezior@users.noreply.github.com> Signed-off-by: Isaac Wilson <isaac.wilson514@gmail.com> Co-authored-by: anurag.ag <anuragagarwal561994@users.noreply.github.com> Co-authored-by: Isaac <10012479+jukie@users.noreply.github.com> Co-authored-by: Arko Dasgupta <arkodg@users.noreply.github.com> Co-authored-by: Isaac Wilson <isaac.wilson514@gmail.com>
1 parent c4db7cf commit ef8f744

38 files changed

Lines changed: 5121 additions & 420 deletions

api/v1alpha1/loadbalancer_types.go

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
1111
// +union
1212
//
1313
// +kubebuilder:validation:XValidation:rule="self.type == 'ConsistentHash' ? has(self.consistentHash) : !has(self.consistentHash)",message="If LoadBalancer type is consistentHash, consistentHash field needs to be set."
14-
// +kubebuilder:validation:XValidation:rule="self.type in ['Random', 'ConsistentHash'] ? !has(self.slowStart) : true ",message="Currently SlowStart is only supported for RoundRobin and LeastRequest load balancers."
14+
// +kubebuilder:validation:XValidation:rule="self.type == 'BackendUtilization' ? has(self.backendUtilization) : !has(self.backendUtilization)",message="If LoadBalancer type is BackendUtilization, backendUtilization field needs to be set."
15+
// +kubebuilder:validation:XValidation:rule="self.type in ['Random', 'ConsistentHash'] ? !has(self.slowStart) : true ",message="Currently SlowStart is only supported for RoundRobin, LeastRequest, and BackendUtilization load balancers."
1516
// +kubebuilder:validation:XValidation:rule="self.type == 'ConsistentHash' && has(self.zoneAware) ? !has(self.zoneAware.preferLocal) : true",message="PreferLocal zone-aware routing is not supported for ConsistentHash load balancers. Use weightedZones instead."
17+
// +kubebuilder:validation:XValidation:rule="self.type == 'BackendUtilization' ? !has(self.zoneAware) : true",message="ZoneAware routing is not supported for BackendUtilization load balancers. BackendUtilization only handles picking endpoints within a single locality."
1618
// +kubebuilder:validation:XValidation:rule="has(self.zoneAware) ? !(has(self.zoneAware.preferLocal) && has(self.zoneAware.weightedZones)) : true",message="ZoneAware PreferLocal and WeightedZones cannot be specified together."
1719
type LoadBalancer struct {
1820
// Type decides the type of Load Balancer policy.
1921
// Valid LoadBalancerType values are
2022
// "ConsistentHash",
2123
// "LeastRequest",
2224
// "Random",
23-
// "RoundRobin".
25+
// "RoundRobin",
26+
// "BackendUtilization".
2427
//
2528
// +unionDiscriminator
2629
Type LoadBalancerType `json:"type"`
@@ -30,6 +33,12 @@ type LoadBalancer struct {
3033
// +optional
3134
ConsistentHash *ConsistentHash `json:"consistentHash,omitempty"`
3235

36+
// BackendUtilization defines the configuration when the load balancer type is
37+
// set to BackendUtilization.
38+
//
39+
// +optional
40+
BackendUtilization *BackendUtilization `json:"backendUtilization,omitempty"`
41+
3342
// EndpointOverride defines the configuration for endpoint override.
3443
// When specified, the load balancer will attempt to route requests to endpoints
3544
// based on the override information extracted from request headers or metadata.
@@ -40,7 +49,7 @@ type LoadBalancer struct {
4049

4150
// SlowStart defines the configuration related to the slow start load balancer policy.
4251
// If set, during slow start window, traffic sent to the newly added hosts will gradually increase.
43-
// Currently this is only supported for RoundRobin and LeastRequest load balancers
52+
// Supported for RoundRobin, LeastRequest, and BackendUtilization load balancers.
4453
//
4554
// +optional
4655
SlowStart *SlowStart `json:"slowStart,omitempty"`
@@ -52,7 +61,7 @@ type LoadBalancer struct {
5261
}
5362

5463
// LoadBalancerType specifies the types of LoadBalancer.
55-
// +kubebuilder:validation:Enum=ConsistentHash;LeastRequest;Random;RoundRobin
64+
// +kubebuilder:validation:Enum=ConsistentHash;LeastRequest;Random;RoundRobin;BackendUtilization
5665
type LoadBalancerType string
5766

5867
const (
@@ -64,6 +73,8 @@ const (
6473
RandomLoadBalancerType LoadBalancerType = "Random"
6574
// RoundRobinLoadBalancerType load balancer policy.
6675
RoundRobinLoadBalancerType LoadBalancerType = "RoundRobin"
76+
// BackendUtilizationLoadBalancerType load balancer policy.
77+
BackendUtilizationLoadBalancerType LoadBalancerType = "BackendUtilization"
6778
)
6879

6980
// ConsistentHash defines the configuration related to the consistent hash
@@ -149,6 +160,63 @@ type Cookie struct {
149160
Attributes map[string]string `json:"attributes,omitempty"`
150161
}
151162

163+
// BackendUtilization defines configuration for Envoy's Backend Utilization policy.
164+
// It uses Open Resource Cost Application (ORCA) load metrics reported by endpoints to make load balancing decisions.
165+
// These metrics are typically sent by the backend service in response headers or trailers.
166+
//
167+
// The backend should report these metrics in header/trailer as one of the following formats:
168+
// - Binary: `endpoint-load-metrics-bin` with base64-encoded serialized `OrcaLoadReport` proto.
169+
// - JSON: `endpoint-load-metrics` with JSON-encoded `OrcaLoadReport` proto, e.g., `JSON {"cpu_utilization": 0.3}`.
170+
// - TEXT: `endpoint-load-metrics` with comma-separated key-value pairs, e.g., `TEXT cpu=0.3,mem=0.8`.
171+
//
172+
// By default, Envoy will forward these ORCA response headers/trailers from the upstream service to the downstream client.
173+
// If the downstream client also uses this information for load balancing, it might lead to unexpected behavior.
174+
// To avoid this, you can use the `HTTPRoute` or `BackendTrafficPolicy` to remove the load report headers before sending the response to the client.
175+
//
176+
// See Envoy proto: envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin
177+
// See ORCA Load Report proto: xds.data.orca.v3.orca_load_report.proto
178+
type BackendUtilization struct {
179+
// A given endpoint must report load metrics continuously for at least this long before the endpoint weight will be used.
180+
// Default is 10s.
181+
// +optional
182+
BlackoutPeriod *gwapiv1.Duration `json:"blackoutPeriod,omitempty"`
183+
184+
// If a given endpoint has not reported load metrics in this long, stop using the reported weight. Defaults to 3m.
185+
// +optional
186+
WeightExpirationPeriod *gwapiv1.Duration `json:"weightExpirationPeriod,omitempty"`
187+
188+
// How often endpoint weights are recalculated. Values less than 100ms are capped at 100ms. Default 1s.
189+
// +optional
190+
WeightUpdatePeriod *gwapiv1.Duration `json:"weightUpdatePeriod,omitempty"`
191+
192+
// ErrorUtilizationPenaltyPercent adjusts endpoint weights based on the error rate (eps/qps).
193+
// This is expressed as a percentage-based integer where 100 represents 1.0, 150 represents 1.5, etc.
194+
//
195+
// For example:
196+
// - 100 => 1.0x
197+
// - 120 => 1.2x
198+
// - 200 => 2.0x
199+
//
200+
// Note: In the internal IR/XDS configuration this value is converted back to a
201+
// floating point multiplier (value / 100.0).
202+
//
203+
// Must be non-negative.
204+
// +kubebuilder:validation:Minimum=0
205+
// +optional
206+
ErrorUtilizationPenaltyPercent *uint32 `json:"errorUtilizationPenaltyPercent,omitempty"`
207+
208+
// Metric names used to compute utilization if application_utilization is not set.
209+
// For map fields in ORCA proto, use the form "<map_field>.<key>", e.g., "named_metrics.foo".
210+
// +optional
211+
MetricNamesForComputingUtilization []string `json:"metricNamesForComputingUtilization,omitempty"`
212+
213+
// KeepResponseHeaders keeps the ORCA load report headers/trailers before sending the response to the client.
214+
// Defaults to false.
215+
// +optional
216+
// +kubebuilder:default=false
217+
KeepResponseHeaders *bool `json:"keepResponseHeaders,omitempty"`
218+
}
219+
152220
// ConsistentHashType defines the type of input to hash on.
153221
// +kubebuilder:validation:Enum=SourceIP;Header;Headers;Cookie;QueryParams
154222
type ConsistentHashType string

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,59 @@ spec:
814814
LoadBalancer policy to apply when routing traffic from the gateway to
815815
the backend endpoints. Defaults to `LeastRequest`.
816816
properties:
817+
backendUtilization:
818+
description: |-
819+
BackendUtilization defines the configuration when the load balancer type is
820+
set to BackendUtilization.
821+
properties:
822+
blackoutPeriod:
823+
description: |-
824+
A given endpoint must report load metrics continuously for at least this long before the endpoint weight will be used.
825+
Default is 10s.
826+
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
827+
type: string
828+
errorUtilizationPenaltyPercent:
829+
description: |-
830+
ErrorUtilizationPenaltyPercent adjusts endpoint weights based on the error rate (eps/qps).
831+
This is expressed as a percentage-based integer where 100 represents 1.0, 150 represents 1.5, etc.
832+
833+
For example:
834+
- 100 => 1.0x
835+
- 120 => 1.2x
836+
- 200 => 2.0x
837+
838+
Note: In the internal IR/XDS configuration this value is converted back to a
839+
floating point multiplier (value / 100.0).
840+
841+
Must be non-negative.
842+
format: int32
843+
minimum: 0
844+
type: integer
845+
keepResponseHeaders:
846+
default: false
847+
description: |-
848+
KeepResponseHeaders keeps the ORCA load report headers/trailers before sending the response to the client.
849+
Defaults to false.
850+
type: boolean
851+
metricNamesForComputingUtilization:
852+
description: |-
853+
Metric names used to compute utilization if application_utilization is not set.
854+
For map fields in ORCA proto, use the form "<map_field>.<key>", e.g., "named_metrics.foo".
855+
items:
856+
type: string
857+
type: array
858+
weightExpirationPeriod:
859+
description: If a given endpoint has not reported load metrics
860+
in this long, stop using the reported weight. Defaults to
861+
3m.
862+
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
863+
type: string
864+
weightUpdatePeriod:
865+
description: How often endpoint weights are recalculated.
866+
Values less than 100ms are capped at 100ms. Default 1s.
867+
pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
868+
type: string
869+
type: object
817870
consistentHash:
818871
description: |-
819872
ConsistentHash defines the configuration when the load balancer type is
@@ -960,7 +1013,7 @@ spec:
9601013
description: |-
9611014
SlowStart defines the configuration related to the slow start load balancer policy.
9621015
If set, during slow start window, traffic sent to the newly added hosts will gradually increase.
963-
Currently this is only supported for RoundRobin and LeastRequest load balancers
1016+
Supported for RoundRobin, LeastRequest, and BackendUtilization load balancers.
9641017
properties:
9651018
window:
9661019
description: |-
@@ -980,12 +1033,14 @@ spec:
9801033
"ConsistentHash",
9811034
"LeastRequest",
9821035
"Random",
983-
"RoundRobin".
1036+
"RoundRobin",
1037+
"BackendUtilization".
9841038
enum:
9851039
- ConsistentHash
9861040
- LeastRequest
9871041
- Random
9881042
- RoundRobin
1043+
- BackendUtilization
9891044
type: string
9901045
zoneAware:
9911046
description: ZoneAware defines the configuration related to the
@@ -1061,14 +1116,23 @@ spec:
10611116
field needs to be set.
10621117
rule: 'self.type == ''ConsistentHash'' ? has(self.consistentHash)
10631118
: !has(self.consistentHash)'
1064-
- message: Currently SlowStart is only supported for RoundRobin and
1065-
LeastRequest load balancers.
1119+
- message: If LoadBalancer type is BackendUtilization, backendUtilization
1120+
field needs to be set.
1121+
rule: 'self.type == ''BackendUtilization'' ? has(self.backendUtilization)
1122+
: !has(self.backendUtilization)'
1123+
- message: Currently SlowStart is only supported for RoundRobin, LeastRequest,
1124+
and BackendUtilization load balancers.
10661125
rule: 'self.type in [''Random'', ''ConsistentHash''] ? !has(self.slowStart)
10671126
: true '
10681127
- message: PreferLocal zone-aware routing is not supported for ConsistentHash
10691128
load balancers. Use weightedZones instead.
10701129
rule: 'self.type == ''ConsistentHash'' && has(self.zoneAware) ?
10711130
!has(self.zoneAware.preferLocal) : true'
1131+
- message: ZoneAware routing is not supported for BackendUtilization
1132+
load balancers. BackendUtilization only handles picking endpoints
1133+
within a single locality.
1134+
rule: 'self.type == ''BackendUtilization'' ? !has(self.zoneAware)
1135+
: true'
10721136
- message: ZoneAware PreferLocal and WeightedZones cannot be specified
10731137
together.
10741138
rule: 'has(self.zoneAware) ? !(has(self.zoneAware.preferLocal) &&

0 commit comments

Comments
 (0)