From 511fa7c452359983e407415a9b235f9e7e8fb907 Mon Sep 17 00:00:00 2001 From: Easwar Swaminathan Date: Fri, 22 May 2026 23:25:17 +0000 Subject: [PATCH 1/4] A119: Slicer LB Policy --- A119-slicer-lb-policy.md | 663 +++++++++++++++++++++++++++ A119_graphics/logical_assignment.png | Bin 0 -> 100487 bytes 2 files changed, 663 insertions(+) create mode 100644 A119-slicer-lb-policy.md create mode 100644 A119_graphics/logical_assignment.png diff --git a/A119-slicer-lb-policy.md b/A119-slicer-lb-policy.md new file mode 100644 index 000000000..a17342ddf --- /dev/null +++ b/A119-slicer-lb-policy.md @@ -0,0 +1,663 @@ +# A119: Slicer LB Policy + +* Author(s): easwars +* Approver: markdroth +* Implemented in: TBD +* Last updated: 2026-05-22 +* Discussion at: TDB + +## Abstract + +Add support for a sharding load balancing policy, that communicates with an +external sharding service to receive resource assignments. This policy should be +supported in both xDS and non-xDS based deployments. + +## Background + +An auto-sharding service enables client-side load balancing through the +following process: + +* Gathering load metrics for keys within an application-defined keyspace +* Dividing the keyspace into distinct, non-overlapping ranges (or slices) +* Assigning specific resources to these key ranges +* Adjusting these mappings in real-time to account for resource availability and + fluctuating load + +Within this framework, application-defined keys generally consist of arbitrary +byte sequences, such as: + +* Tenant identifiers for multi-tenant architectures +* Individual User IDs +* Identifiers created via hashing + +The targets for traffic distribution, or resources, frequently include: + +* Application servers +* Kubernetes pods within a cluster +* Regions within a multi-regional service deployment + +Implementing a load balancing policy in gRPC that uses an auto-sharding service +has applications in various scenarios, such as: + +* Enhancing request affinity in stateful environments +* Improving isolation and system resilience for multi-tenant services +* Supporting hybrid setups spanning Borg and GCP infrastructures +* Providing the scalability required for rapid growth in AI-driven applications + +### Related Proposals + +* [A42: xDS Ring Hash LB Policy][A42] +* [A57: XdsClient Failure Mode Behavior][A57] +* [A62: Pick First][A62]] +* [A102: xDS GrpcService Support][A102] +* [OSS DynamicSharding gRPC Protocol Spec](TBD) + +## Proposal + +Add the `slicer_experimental` LB policy in gRPC that contains the following +functionality: + +* Utilizing the OSS DynamicSharding gRPC protocol for communicating with an + auto-sharding service and processing assignments from that service. + * These assignments will partition an application-defined keyspace into + distinct, non-overlapping slices, each associated with a specific set of + server endpoints. +* Mapping client application requests to a specific key within the + application-defined keyspace. +* Identifying the matching key range and choosing a server endpoint assigned to + it. +* Reporting real-time load metrics back to the auto-sharding service. +* Providing a fallback mechanism to route client traffic when assignments from + the auto-sharding service are unusable. + +Crucially, the LB policy receives its configuration and endpoint data from the +Name Resolver and not from the auto-sharding service. + +### Supported modes of operation + +The slicer_experimental LB policy must support two primary modes of operation: + +* An LB policy that performs both locality and endpoint picking: + * In xDS use-cases, such an LB policy receives endpoints across all + localities and shards requests accordingly. This is similar to how the + `ring_hash` LB policy, specified in [gRFC A42][A42], works. + * In non-xDS use-cases, such an LB policy will be configured as the top-level + LB policy, sharding request across a flat list of endpoints provided by the + Name Resolver. +* An LB policy that only performs endpoint picking: + * In xDS use-cases, such an LB policy will be configured under a policy like + `weighted_target_experimental` that handles locality picking, while each + `slicer_experimental` child policy instance only handles endpoint picking + within its specific locality. + +The `slicer_experimental` policy maintains consistent behavior across both modes +and does not require explicit knowledge of its operational context. Notably, we +do not support using this LB policy solely for locality picking with delegation +to a separate endpoint-picking policy. This configuration lacks identified use +cases and introduces significant implementation complexity. + +### Load Balancing Configuration + +The `slicer_experimental` LB policy's configuration will be as follows: + +```proto +message SlicerLbConfig { + // Name of the auto-sharding service, as a gRPC target URI. + string sharding_service_target_uri = 1; + +// An identifier sent to the sharding service. Assignments and load reports are +// scoped to this identifier. +// +// Can optionally contain up to two "%s" tokens. The first is replaced with the +// "Backend Service" and the second with the "Locality" before sending. If a +// token is present, but the corresponding information is not available to the +// LB policy, the token will be replaced with an empty string. + string slicing_target = 3; + +// Name of the request header containing the application-defined key. This key +// is used to look up the matching key range (slice) assigned by the sharding +// service. + string slice_key_header_name = 4; + + // Mode used to pick an endpoint for a request. + enum EndpointPickingMode { + RANDOM = 0; + } + + // Mode used to pick an endpoint from a matching key range. + // If unset, defaults to RANDOM. + EndpointPickingMode slice_picking_mode = 5; + + // Mode used to pick an endpoint when using the fallback mechanism. + // If unset, defaults to RANDOM. + EndpointPickingMode fallback_picking_mode = 6; + + // Names of load metrics to send to the external sharding service. + repeated string load_metric_keys = 7; +} +``` + +Key considerations regarding the LB policy configuration: + +* The configuration specifies the auto-sharding service's target URI but + deliberately omits credentials to be used for this communication. This + decision prevents potential privilege-escalation vulnerabilities resulting + from a compromised control plane, following the security framework established + in [gRFC A102][A102]. +* Per-request gRPC metadata for the sharding service is omitted from the + configuration. While the xDS `GrpcService` proto can define initial metadata + to be included on every stream to the external service, the current + OSS DynamicSharding protocol does not require it. + * Excluding this field now maintains future extensibility without increasing + implementation complexity. + +### Handling updates from the Name Resolver + +When the LB policy receives a configuration update, it must do the following: + +* If the `sharding_service_target_uri` field has changed (or if this is the + first configuration update), use a “Channel Factory” to [create a new gRPC + channel to this target URI](#creating-a-grpc-channel-to-the-sharding-service). + If a new gRPC channel is created: + * Create a new `Shard` stream on the newly created gRPC channel, and, + * Close the previously created gRPC channel to the sharding service +* If the `slicing_target` field has changed, create a new `Shard` stream because + the `slicing_target` controls the assignments sent by the sharding service. +* If the `load_metric_keys` field has changed: TBD + +#### Managing endpoints received from the Name Resolver + +The `slicer_experimental` LB policy must create a `pick_first` child for every +endpoint that it receives from the Name Resolver, and the latter will create +subchannels for the addresses within the endpoints. + +In Go, a utility LB policy exists, named `endpointsharding` that takes care of +this functionality. The `slicer_experimental` LB policy creates a single +`endpointsharding` child and forwards all the endpoints to this child, which will +create one `pick_first` child per endpoint. The `endpointsharding` child will return +the connectivity state and picker for every endpoint, and the +`slicer_experimental` uses this to compute the aggregated connectivity state for +the gRPC channel and its own picker. See [The Picker](#the-picker) section for +more details. + +The LB policy should maintain a map, that is updated based on updates from the +`endpointsharding` child and consulted when a new picker is built. The key for +this map is the hostname attribute on the endpoint received from the Name +Resolver and the value is the state associated with that endpoint. The value +must contain the following: + +* The connectivity state of the child `pick_first` LB policy for that endpoint +* The most recent picker returned by the child `pick_first` LB policy for that + endpoint + +Whenever the LB policy receives new endpoints from the Name Resolver, it must +create a new [SliceMap](#the-slicemap) (possibly based on a copy of the existing +one) and create a new picker using it. See section [Constructing a +SliceMap](#constructing-a-slicemap) for more information. + +If the LB policy receives an empty set of endpoints from the Name Resolver, it +must set the connectivity state of the gRPC channel to `TRANSIENT_FAILURE` and +fail all subsequent RPCs until an update with a non-empty set of endpoints is +received. + +### Creating a gRPC channel to the sharding service + +The LB policy will be injected with a “Channel Factory” via attributes, +alongside its configuration. This utility will help create a fully functional +gRPC channel given a target URI. In xDS-based deployments, this “Channel +Factory” will be injected by the `cds_experimental` LB policy. Refer to section +[Changes to CDS LB policy](#changes-to-cds-lb-policy) for more details. For +non-xDS environments, users will have the capability to inject this utility via +a dedicated channel option. + +#### Go + +The “Channel Factory” or provider is defined as a function type that accepts the +target URI as a string, and returns a gRPC channel. The existing +`grpc.ClientConnInterface` interface, instead of the concrete `*grpc.ClientConn` +type, is used to represent a gRPC channel, to allow for wrapping. The LB policy +can create a client stub to the sharding service by passing this interface to +the protobuf generated code and make RPCs using that client stub. + +```golang +package grpc + +// A factory to create a grpc.ClientConn to the given target URI. +// +// The second return value is a cancel function that the caller must invoke +// once they are done using the returned grpc.ClientConn. +type ClientConnProvider func(string) (ClientConnInterface, func(), error) +``` + +A `DialOption` will be added to allow the user to inject a “Channel Factory”. +gRPC will take care of plumbing this down to the LB policies. + +```golang +package grpc + +// WithClientConnProvider returns a dial option that makes the channel provider +// available to LB policies. +func WithClientConnProvider(f ClientConnProvider) DialOption { ... } +``` + +We will also have APIs to set and get this factory from the `resolver.State` +struct that is sent to the LB policy as part of a resolver update. + +```golang +package grpc + +// ClientConnProviderFromResolverState returns a ClientConnProvider from the +// given resolver state, or nil if not present. +func ClientConnProviderFromResolverState(state resolver.State) ClientConnProvider { ... } + +// SetClientConnProvider returns a copy of the resolver state with the provider +// set as an attribute. +func SetClientConnProvider(s resolver.State, p ClientConnProvider) resolver.State { ... } +``` + +#### C++ + +TBD + +#### JAVA + +TBD + +### Communicating with the sharding service + +The LB policy communicates with an external sharding service using the OSS +DynamicSharding gRPC protocol. As described earlier, the LB policy creates a +gRPC channel to the sharding service using the “Channel Factory” provided to it, +whenever the `sharding_service_target_uri` in its configuration changes. It will +then create a `Shard` stream on that channel. + +#### Sending the first message + +The LB policy sends an `Init` message on the stream to kick things off. This +message currently contains three fields: + +* `target`: The value for this field is derived from the `slicing_target` field + of the LB policy configuration. If `%s` tokens are present in this string, + they are replaced with the “Backend Service” and “Locality” values passed to + the LB policy as attributes in the resolver update (similar to how the + “Channel Factory” is passed). + * In xDS use-cases, the “Backend Service” and “Locality” attributes are + already available: + * The “Backend Service” attribute is currently set by the + `xds_cluster_impl_experimental` LB policy, for consumption by the endpoint + picking policy. + * The “Locality” attribute is currently set by the `cds_experimental` LB + policy, for consumption by the locality picking policy. + * In non-xDS use-cases, the common case is for the `slicing_target` to not + contain `%s` tokens. But if they do, it is the responsibility of the user to + ensure that these attributes are populated by the Name Resolver. If these + attributes are not available, the LB policy will replace these tokens with + empty strings. +* `client_uuid`: The LB policy generates a UUID at creation time and must reuse + the same value across stream restarts. +* `current_generation`: The LB policy must store the generation number of the + most recent good assignment received from the sharding service and use that + value here. + +#### Handling responses from the sharding server + +Responses received from the sharding server in a `ShardingResponse` message can +one of the following: + +* `LoadReportingConfig`: This contains configuration for how load needs to be + aggregated and sent to the sharding server. See section on [Load + Reporting](#load-reporting) for more information. +* `AssignmentChunk`: This contains one chunk of a logical assignment from the + sharding server. The LB policy must cache chunks until it receives an + `AssignmentMetadata` message. +* `AssignmentMetadata`: This indicates the end of a logical assignment from the + sharding server. The LB policy must attempt to combine previously received + chunks into one single logical assignment. + +See section on [Handling assignments from the sharding +server](#handling-assignments-from-the-sharding-server) for more information. + +#### Backoff on stream and connectivity failures + +When a `Shard` stream fails without receiving at least one good logical +assignment, the LB policy must use exponential backoff before each successive +attempt to re-establish the stream. The algorithm should be similar to what gRPC +uses for connection attempts. The backoff state will be reset when a `Shard` +stream finally receives a good logical assignment from the server. + +Implementations should use the `wait_for_ready` option on the `Shard` stream to +help recover faster from connectivity failures instead of applying a backoff +when stream creation fails. This is in contrast to what the XdsClient does (as +described in [gRFC A57][A57]), and is considered acceptable here because there +is not much the LB policy can do with these connectivity errors other than +simply logging it. When connectivity to the sharding server is broken and there +are no previously received assignments, the LB policy must use the fallback +option described in the section [Fallback mechanism](#fallback-mechanism) +section. + +#### Handling assignments from the sharding server + +The sharding server implementing the OSS DynamicSharding gRPC protocol will +distribute (chunked) complete assignments to its clients, instead of deltas. +From the `slicer_experimental` LB policy’s point of view, this will look as +follows: + +* A single logical assignment is split into multiple `ShardingResponse` messages +* Each `ShardingResponse` message contains either an `AssignmentChunk` message + or an `AssignmentMetadata` message. +* Each `AssignmentChunk` message contains a list of `SliceAssignment` messages + and a list of `EndpointState` messages (each of which contains a single + endpoint name). +* Each `SliceAssignment` message contains a `Slice` that contains a `[start_key, + end_key)` and a list of endpoint indices into the combined endpoint list over + all chunks (in chunk order) +* The `AssignmentMetadata` message indicates that the sharding server has + completed sending all chunks for the current assignment and contains a + generation number for the logical assignment. + +Visually, we can represent this as follows: + +![Logical Assignment](A119_graphics/logical_assignment.png) + +The LB policy must cache the `AssignmentChunk` messages locally until it sees an +`AssignmentMetadata` message. This is because each `Chunk` contains several +endpoint names and each `Slice` within a chunk contains an index into the +complete set of endpoint names, combined in chunk order. So, until all chunks +are received, the LB policy cannot meaningfully use any of them. + +Once the `AssignmentMetadata` message is received, the LB policy must build a +`SliceMap` data structure. See [The SliceMap](#the-slicemap) section for more +information on how to build this data structure and its internals. If building +the `SliceMap` fails, the LB policy must terminate the stream to the sharding +service, and attempt to re-establish it. + +Once a `SliceMap` is built successfully, the LB policy must create a new picker +with the newly built `SliceMap` and send an update to the gRPC channel. + +### The SliceMap + +The `SliceMap` is the most important data structure within the +`slicer_experimental` LB policy. The most recently built `SliceMap` should be +stored within the LB policy and a reference to it is passed to the picker. Any +server implementing the OSS DynamicSharding protocol will send complete +assignments, and not deltas, and therefore the `slicer_experimental` LB policy +should build a brand new `SliceMap` whenever it receives a new logical +assignment from the sharding server. When the LB policy receives updates from +the `pick_first` children though, it could make a copy of the existing +`SliceMap` and only update the endpoint state stored in it before creating a new +picker. In any case, the `SliceMap` must be immutable to allow the picker to +access it without having to acquire a mutex. + +While the exact choice of the underlying data structures are left to the +implementation’s choice, here is a general idea of what a `SliceMap` would look +like: + +```golang +// An arbitrary set of bytes representing a key in the application defined key +// space. +struct slice_key { + key: []byte // At most 512 bytes + is_infinity: bool // Sentinel key +} + +// A key range that includes start, but does not include end. +struct slice_range { + start: slice_key // Inclusive + end: slice_key // Exclusive (can be positive infinity sentinel) +} + +// State associated with a single endpoint or backend instance. +struct endpoint_state { + hostname: string + connectivity_state: enum // From child pick_first (e.g. READY, TRANSIENT_FAILURE) + picker: Picker // Picker returned by the child pick_first +} + +// The collection of endpoints associated with a specific slice. +struct assigned_endpoints { + all_endpoints: []endpoint_state // Full list of endpoints assigned to this slice + ready_endpoints: []endpoint_state // Endpoints currently in READY state + in_fallback: boolean // True when all endpoints are in TRANSIENT_FAILURE +} + +// A slice from the sharding server and its associated endpoint resources. +struct slice_entry { + range: slice_range + assigned_endpoints: assigned_endpoints +} + +// Complete SliceMap stored in the LB policy and in the Picker. +struct slice_map { + // Ordered list of entries sorted by slice_key, where slice_key is the + // slice_range.end associated with the specific slice. This support O(log N) + // lookup for a matching entry given a key. + sorted_slices: []pair(slice_key, slice_entry) + + // Received from the sharding server. + generation_number: int64 + + // State for all endpoints received from the Name Resolver. Used when all + // endpoints in a matching range are in TRANSIENT_FAILURE. + fallback_entry: assigned_endpoints +} +``` + +#### Constructing a SliceMap + +When the LB policy receives a complete logical assignment from the sharding +service, indicated by the receipt of an `AssignmentMetadata` message, it must +create a new `SliceMap` by doing the following: + +* Combine the list of endpoint names into one list, in chunk order +* Create one `slice_entry` for each `Slice` in the assignment data. + * Iterate through the list of endpoint indices in the `Slice` an` figure out + the corresponding endpoint name. Lookup the endpoints map in the LB policy + to find the matching `endpointState` for the hostname. + * Add an entry to the `all_endpoints` list with this state + * If the endpoint is `READY`, also add the state to the `ready_endpoints` + list + * If no matching `endpointState` exists in the endpoints map, add an entry + to the `all_endpoints` list that only contains the hostname field. + * If all endpoints belonging to the `Slice` are in `TRANSIENT_FAILURE`, set + the `in_fallback` bit +* Create the `fallback_endpoints` array with state for all endpoints received from + the resolver. +* Validate the `SliceMap` by ensuring that there are no gaps in the key ranges. + The sharding server is expected to cover the entire key space. +* If validation succeeds, update the `generation_number` field to the value + specified in the `AssignmentMetadata` message. Else, throw away the cached + assignment data and close the ongoing stream with the sharding server. + +When the LB policy receives a new set of endpoints from the Name Resolver, it +must send the endpoints to its child policy. And once it receives an update from +the child policy, it must update the endpoints map. Once this is done, it must +build a new `SliceMap`. If one already exists, it should make a copy of it, and +update only the endpoint states. As a special case, when there are no +assignments from the sharding service yet, the LB policy must create a new +`SliceMap` that only contains the `fallback_endpoints`. + +### The Picker + +The LB policy must create a new picker every time one of the following events +happens: + +* A new logical assignment is received from the sharding service +* An update is received from its child policy because the connectivity state of + one of the endpoints has changed + +The picker is given the `SliceMap` and the name of the request header from which +it can extract the key for the incoming request. Here is the pseudo-code for the +`Pick` method of the picker: + +```golang +func Pick(request): + // Extract the key from the specified header + target_key = request.headers.get(slice_key_header_name) + if target_key is empty: + FAIL pick with status set to UNAVAILABLE + return + + // Look up the matching key range. Guaranteed to find a match as long at + // least one logical assignment has been received, as assignments are + // validated to not contain gaps + slice_entry = SliceMap.find_matching_range(target_key) + if slice_entry is nil: + // Special case where endpoints are available, but assignments are not + delegate_pick(slice_entry.fallback_entry) + return + + + // Check for fallback + if slice_entry.in_fallback == true: + if slice_entry.fallback_entry.in_fallback == true: + FAIL the pick // All endpoints are in TF + return + else: + delegate_pick(slice_entry.fallback_entry) + return + else: + delegate_pick(slice_entry) + return + +func delegate_pick(entry): + // Select a random endpoint + selected_endpoint = entry.all_endpoints.random() + + // Use it if in READY state + if selected_endpoint.status == READY: + selected_endpoint.picker.Pick(request) + return + + // Handle IDLE state + if selected_endpoint.status == IDLE: + start_background_connection(selected_endpoint) + + // Find a random READY endpoint + ready_endpoint = entry.ready_endpoints.random() + if ready_endpoint is not nil: + ready_endpoint.picker.Pick(request) + return + else: + QUEUE the pick + return + + // Handle CONNECTING or TRANSIENT_FAILURE states + if selected_endpoint.status == CONNECTING or TRANSIENT_FAILURE: + // Wake up the first IDLE endpoint we can find + curr_idx = selected_endpoint.idx() + for (i = 1; i < len(entry.all_endpoints); i++): + ep = entry.all_endpoints[(curr_idx + i) % len(entry.all_endpoints)] + if ep.status == IDLE: + start_background_connection(ep) + break // Only trigger connection on the first IDLE one found + + ready_endpoints = entry.ready_endpoints.random() + if ready_endpoint is not nil: + ready_endpoint.picker.Pick(request) + return + else: + QUEUE the pick + return +``` + +### Subchannel State Handling + +Subchannels will start in state `IDLE`, and the `slicer_experimental` policy +will not proactively connect to them. When the picker chooses a random endpoint +from the matching `slice_entry` for a call, if the associated subchannel is not +`READY`, the picker will trigger a connection attempt for the first `IDLE` +subchannel, as described in the picker pseudo-code, and the subchannel will +transition to state `CONNECTING`. + +If the connection attempt is successful, the subchannel will transition to state +`READY`. If the connection attempt is not successful, the subchannel will move +to `TRANSIENT_FAILURE`, and will remain there until it successfully connects, at +which point it will move to READY. Once the subchannel moves to +`TRANSIENT_FAILURE`, the pick_first child will continuously try to reconnect +(with exponential backoff), as specified in the sticky `TRANSIENT_FAILURE` +behavior in [gRFC A62][A62]. + +### Aggregated Connectivity State + +The behavior will be exactly the same as that of the ring_hash policy, as +described in [gRFC A42][A42]. Highlights here are: + +* The LB policy starts off in `IDLE`, unlike most policies that start off in + `CONNECTING` +* The LB policy uses a heuristic and reports `TRANSIENT_FAILURE` when at least + two subchannels are in `TRANSIENT_FAILURE` and none of the subchannels are + `READY` +* When the LB policy reports `TRANSIENT_FAILURE` or `CONNECTING`, it ensures + that there is at least one subchannel that is actively trying to connect, + giving itself a chance to move to `READY` even when it is not getting picks. + +### Fallback Mechanism + +The `slicer_experimental` LB policy must employ a fallback mechanism that +utilizes all endpoints provided by the Name Resolver when one of the following +conditions are met: + +* All the endpoints in the matching `slice_entry` for a request are in + `TRANSIENT_FAILURE` state + * The picker takes care of this by using the `fallback_entry` field in the + `SliceMap` when a matching `slice_entry` is in fallback mode. +* No good logical assignments have been received from the sharding service yet, + but endpoints have been received from the Name Resolver + * The LB policy takes care of this by creating a `SliceMap` that does not have + any `slice_entry`s, but has the `fallback_entry` field set + +The LB policy must also continue using previously received good assignments from +the sharding service, if it subsequently receives a bad one. The LB policy +should update the `SliceMap` only if the received assignments are valid, and +thereby take care of this requirement. + +### Load Reporting + +TBD + +### xDS integration + +TBD + +#### xDS LB policy configuration + +TBD + +#### Changes to xDS LB Registry + +TBD + +#### Child policy config generation + +TBD + +#### Changes to XdsClient + +TBD + +#### Changes to CDS LB policy + +TBD + +### Temporary environment variable protection + +TBD + +## Rationale + +### Why not create a child LB policy for every `slice_entry`? + +TBD + +### Why create connections lazily? + +TBD + +## Implementation + +Will be implemented in Go first, closely followed by Java and C++. + +[A42]: A42-xds-ring-hash-lb-policy.md +[A57]: A57-xds-client-failure-mode-behavior.md +[A62]: A62-pick-first.md +[A102]: (https://github.com/grpc/proposal/pull/510) diff --git a/A119_graphics/logical_assignment.png b/A119_graphics/logical_assignment.png new file mode 100644 index 0000000000000000000000000000000000000000..d95c37a0adb2e00dc3091870f7d6934a834db4a4 GIT binary patch literal 100487 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 literal 0 HcmV?d00001 From 0a8f625fb7086ca4ae1c38f108870aa6e932633a Mon Sep 17 00:00:00 2001 From: Easwar Swaminathan Date: Tue, 26 May 2026 21:40:19 +0000 Subject: [PATCH 2/4] fill in a couple of xDS sections --- A119-slicer-lb-policy.md | 130 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/A119-slicer-lb-policy.md b/A119-slicer-lb-policy.md index a17342ddf..7798aa684 100644 --- a/A119-slicer-lb-policy.md +++ b/A119-slicer-lb-policy.md @@ -47,6 +47,7 @@ has applications in various scenarios, such as: ### Related Proposals * [A42: xDS Ring Hash LB Policy][A42] +* [A52: gRPC xDS Custom Load Balancer Configuration][A52] * [A57: XdsClient Failure Mode Behavior][A57] * [A62: Pick First][A62]] * [A102: xDS GrpcService Support][A102] @@ -617,15 +618,135 @@ TBD ### xDS integration -TBD +In xDS-based deployments, client applications can be configured to use the +`slicer_experimental` LB policy by leveraging gRPC's support for custom LB +policies, as described in [gRFC A52][A52]. The xDS management server will set +the +[load_balancing_policy](https://github.com/envoyproxy/envoy/blob/d26361ac44e48ad347afbaff141c5c0387d48c40/api/envoy/config/cluster/v3/cluster.proto#L1229) +field of the +[Cluster](https://github.com/envoyproxy/envoy/blob/d26361ac44e48ad347afbaff141c5c0387d48c40/api/envoy/config/cluster/v3/cluster.proto#L50) +resource appropriately. + +As mentioned in the [Supported modes of +operation](#supported-modes-of-operation) section, client applications can be +configured to use the `slicer_experimental` LB policy for both locality and +endpoint picking, by setting the `load_balancing_policy` field to an instance of +the `Slicer` protobuf message described in the next section. To use the +`slicer_experimental` LB policy *only* for endpoint picking, the +`load_balancing_policy` field could be set to a locality picking policy like +[WrrLocality](https://github.com/envoyproxy/envoy/blob/d26361ac44e48ad347afbaff141c5c0387d48c40/api/envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto#L21) +and setting the `endpoint_picking_policy` field inside it to the `Slicer` +protobuf message described below. #### xDS LB policy configuration -TBD +A new message type that represents the configuration for the +`slicer_experimental` LB policy will be added to the envoy repository in the +[api/envoy/extensions/load_balancing_policies](https://github.com/envoyproxy/envoy/tree/main/api/envoy/extensions/load_balancing_policies) +directory. + +```proto +import "envoy/config/core/v3/grpc_service.proto"; -#### Changes to xDS LB Registry +message Slicer { + // Configuration for the gRPC service that the LB policy will communicate with + // to receive sharding assignments from and to send load reports to. + config.core.v3.GrpcService grpc_service = 1 -TBD +// An identifier sent to the sharding service. Assignments and load reports are +// scoped to this identifier. +// +// Can optionally contain up to two "%s" tokens. The first is replaced with the +// "Backend Service" and the second with the "Locality" before sending. If a +// token is present, but the corresponding information is not available to the +// LB policy, the token will be replaced with an empty string. + string slicing_target = 3; + +// Name of the request header containing the application-defined key. This key +// is used to look up the matching key range (slice) assigned by the sharding +// service. + string slice_key_header_name = 4; + + // Mode used to pick an endpoint for a request. + enum EndpointPickingMode { + RANDOM = 0; + } + + // Mode used to pick an endpoint from a matching key range. + // If unset, defaults to RANDOM. + EndpointPickingMode slice_picking_mode = 5; + + // Mode used to pick an endpoint when using the fallback mechanism. + // If unset, defaults to RANDOM. + EndpointPickingMode fallback_picking_mode = 6; + + // Names of load metrics to send to the external sharding service. + repeated string load_metric_keys = 7; +} +``` + +While most of the fields in the above proto are similar to the fields in the +[Load Balancing Configuration](#load-balancing-configuration) section, the +notable difference is the use of the +[GrpcService](https://github.com/envoyproxy/envoy/blob/d26361ac44e48ad347afbaff141c5c0387d48c40/api/envoy/config/core/v3/grpc_service.proto#L29) +protobuf message to specify the configuration for the auto-sharding service. + +* gRPC only supports the `google_grpc` field inside the `target_specifier` + field. If this field is not set, the `Cluster` resource must be NACKed. +* gRPC ignores the `timeout` field because the RPC to the sharding service uses + bidi-streaming. +* gRPC ignores the `initial_metadata` and `retry_policy` fields because the OSS + DynamicSharding gRPC protocol has no current use case for these. +* The credentials used to communicate with the external auto-sharding service + will be the ones specified in the `GrpcService` proto, if the xDS management + server is a trusted server. Else, it will be based on the + `allowed_grpc_services` field of the bootstrap configuration. See [gRFC + A102][A102] for more details. + +#### Changes to xDS LB Policy Registry + +The xDS LB Policy Registry API described in [gRFC A52][A52] will be enhanced to +support the two new bits of functionality, as follows: + +1. Parsing a `GrpcService` proto embedded within an LB policy's configuration + into its internal representation, requires access to the following: + * the complete bootstrap configuration to access the `allowed_grpc_services` + section of the bootstrap configuration. + * configuration of the specific xDS server that delivered this resource, to + determine if the server is to be trusted or not. +1. Returning additional information (like the parsed internal representation of + the `GrpcService` proto), other than the currently returned gRPC LB + policy configuration (in JSON format), to be forwarded to the LB policies. + +In Go, the existing `converter` type will be modified as follows: + +```golang +// ConverterOptions contains options passed to the Converter. +type ConverterOptions struct { + // BootstrapConfig is the complete xDS bootstrap configuration. + BootstrapConfig *bootstrap.Config + // ServerConfig is the configuration of the xDS server from which the + // resource was received. + ServerConfig *bootstrap.ServerConfig +} + +// LBPolicyInfo contains information to be passed to the LB policy, outside of +// its configuration. +type LBPolicyInfo struct { + // GRPCService is the internal parsed representation of a GrpcService proto + // that was present in the xDS LB policy configuration. + GRPCService InternalGRPCService + +} + +// Converter converts raw proto bytes into JSON LB policy configuration. +// +// Returns the following: +// - converted JSON form of the LB policy configuration +// - Additional information to be passed to the LB policy, and, +// - Any error encountered during the conversion. +type Converter func(rawProto []byte, depth int, opts ConverterOptions) (json.RawMessage, LBPolicyInfo, error) +``` #### Child policy config generation @@ -658,6 +779,7 @@ TBD Will be implemented in Go first, closely followed by Java and C++. [A42]: A42-xds-ring-hash-lb-policy.md +[A52]: A52-xds-custom-lb-policies.md [A57]: A57-xds-client-failure-mode-behavior.md [A62]: A62-pick-first.md [A102]: (https://github.com/grpc/proposal/pull/510) From 606553915f5b5504fea91481db554cd54d928c6a Mon Sep 17 00:00:00 2001 From: Easwar Swaminathan Date: Tue, 26 May 2026 21:42:45 +0000 Subject: [PATCH 3/4] fix proto formatting --- A119-slicer-lb-policy.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/A119-slicer-lb-policy.md b/A119-slicer-lb-policy.md index 7798aa684..037ca6a6b 100644 --- a/A119-slicer-lb-policy.md +++ b/A119-slicer-lb-policy.md @@ -653,19 +653,19 @@ message Slicer { // to receive sharding assignments from and to send load reports to. config.core.v3.GrpcService grpc_service = 1 -// An identifier sent to the sharding service. Assignments and load reports are -// scoped to this identifier. -// -// Can optionally contain up to two "%s" tokens. The first is replaced with the -// "Backend Service" and the second with the "Locality" before sending. If a -// token is present, but the corresponding information is not available to the -// LB policy, the token will be replaced with an empty string. - string slicing_target = 3; - -// Name of the request header containing the application-defined key. This key -// is used to look up the matching key range (slice) assigned by the sharding -// service. - string slice_key_header_name = 4; + // An identifier sent to the sharding service. Assignments and load reports are + // scoped to this identifier. + // + // Can optionally contain up to two "%s" tokens. The first is replaced with the + // "Backend Service" and the second with the "Locality" before sending. If a + // token is present, but the corresponding information is not available to the + // LB policy, the token will be replaced with an empty string. + string slicing_target = 2; + + // Name of the request header containing the application-defined key. This key + // is used to look up the matching key range (slice) assigned by the sharding + // service. + string slice_key_header_name = 3; // Mode used to pick an endpoint for a request. enum EndpointPickingMode { @@ -674,14 +674,14 @@ message Slicer { // Mode used to pick an endpoint from a matching key range. // If unset, defaults to RANDOM. - EndpointPickingMode slice_picking_mode = 5; + EndpointPickingMode slice_picking_mode = 4; // Mode used to pick an endpoint when using the fallback mechanism. // If unset, defaults to RANDOM. - EndpointPickingMode fallback_picking_mode = 6; + EndpointPickingMode fallback_picking_mode = 5; // Names of load metrics to send to the external sharding service. - repeated string load_metric_keys = 7; + repeated string load_metric_keys = 6; } ``` From 5d79ad67b889cf9456a65c09c6adbb68c3902a27 Mon Sep 17 00:00:00 2001 From: Easwar Swaminathan Date: Thu, 4 Jun 2026 21:13:42 +0000 Subject: [PATCH 4/4] fill in couple of more xDS sections --- A119-slicer-lb-policy.md | 76 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/A119-slicer-lb-policy.md b/A119-slicer-lb-policy.md index 037ca6a6b..01ce0c677 100644 --- a/A119-slicer-lb-policy.md +++ b/A119-slicer-lb-policy.md @@ -706,7 +706,7 @@ protobuf message to specify the configuration for the auto-sharding service. #### Changes to xDS LB Policy Registry The xDS LB Policy Registry API described in [gRFC A52][A52] will be enhanced to -support the two new bits of functionality, as follows: +support two new bits of functionality, as follows: 1. Parsing a `GrpcService` proto embedded within an LB policy's configuration into its internal representation, requires access to the following: @@ -718,7 +718,7 @@ support the two new bits of functionality, as follows: the `GrpcService` proto), other than the currently returned gRPC LB policy configuration (in JSON format), to be forwarded to the LB policies. -In Go, the existing `converter` type will be modified as follows: +In Go, the existing `Converter` type will be modified as follows: ```golang // ConverterOptions contains options passed to the Converter. @@ -750,11 +750,75 @@ type Converter func(rawProto []byte, depth int, opts ConverterOptions) (json.Raw #### Child policy config generation -TBD +The `ClusterUpdate` struct is gRPC's internal representation of the xDS cluster +resource. A new field `LBPolicyInfo` will be added to this struct to carry +additional information to be conveyed to the LB policy, in additional to the +existing field `LBPolicy` that carries the LB policy configuration. + +```golang +package xdsresource + +type ClusterUpdate struct { + // Existing fields redacted + + // LBPolicyInfo contains additional information to be passed to the LB policy, + // outside of its configuration. + LBPolicyInfo LBPolicyInfo + + // LBPolicy represents the locality and endpoint picking policy in JSON, + // which will be the child policy of xds_cluster_impl. + LBPolicy json.RawMessage +} +``` + +The existing logic to parse the xDS cluster resource will remain mostly +untouched apart from populating the above mentioned new field when returned by +the xDS LB Policy Registry. #### Changes to XdsClient -TBD +The `XdsClient` fundamentally operates as two distinct components: + +* **The Transport Layer**: Responsible for maintaining the ADS (Aggregated + Discovery Service) stream to the management server, requesting resources, + handling ACKs/NACKs etc. +* **Resource-Specific Logic**: Handles parsing incoming resources and converting + them into internal representations for use by the rest of the gRPC stack. + +While the `GrpcService` protobuf message is part of the `slicer_experimental` LB +policy configuration, its parsing logic should not reside within +`ClusterResourceType`, which contains functionality to parse incoming `Cluster` +resources. This protobuf message can also be embedded in HTTP filter +configurations within `Listener` and `RouteConfiguration` resources (as detailed +in gRFCs A92[A92] and A93[A93]). Decoupling the parsing logic ensures it remains +reusable across all these contexts. + +In Go, a new function will be added to the `xdsresource` package that can be +shared by all the resource-type implementations to parse `GrpcService` protobuf +messages into their internal representation. + +```golang +package xdsresource + +import ( + v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + google.golang.org/grpc/internal/xds/bootstrap +) + +// ParseGRPCService converts a GrpcService proto into its internal +// representation. +func ParseGRPCService(*v3corepb.GrpcService, *bootstrap.Config, *bootstrap.ServerConfig) (*InternalGRPCService, error) { + // Determine channel and call credentials to use: + // - If `trusted_xds_server` bit is set in `ServerConfig`, use credentials + // from the GrpcService proto + // - Else, consult the `allowed_grpc_services` map in `Config` to determine if + // the `GrpcService` is in the allowed list of services. + // - If allowed, use credentials specified in the bootstrap config + // - Else, return error + + // Parse other fields and convert to internal representation. +} +``` #### Changes to CDS LB policy @@ -782,4 +846,6 @@ Will be implemented in Go first, closely followed by Java and C++. [A52]: A52-xds-custom-lb-policies.md [A57]: A57-xds-client-failure-mode-behavior.md [A62]: A62-pick-first.md -[A102]: (https://github.com/grpc/proposal/pull/510) +[A92]: https://github.com/grpc/proposal/pull/481 +[A93]: https://github.com/grpc/proposal/pull/484 +[A102]: https://github.com/grpc/proposal/pull/510