Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions content/en/docs/guides/ssa.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Stateful Session Affinity in gRPC: A Deep Dive

## Overview

Stateful session affinity is a load balancing technique that ensures all RPCs
belonging to a specific session are routed to the same backend. This is achieved
by using HTTP cookies as an identifier, which the gRPC client's xDS load
balancing logic uses to consistently route RPCs to a specific backend.

This is helpful in many cases:

- Caching data per session: Where each backend caches data specific to a user's
session.
- Maintaining application state: Where a backend needs to maintain an active
context for a specific user session.
- Real-time interaction: For example, gaming servers where users need
to be connected to the same instance.

## How it Works: A Step-by-Step Breakdown

1. The first RPC in a new session does not include a session cookie. The gRPC
client uses a configured load balancing policy to select a backend to service
the RPC. Upon receiving the response, a client-side gRPC filter generates
a session cookie containing information about the selected backend (such as
base64-encoded address and cluster name). This cookie is then included in
the response metadata provided back to the user application. Users should
treat the cookie's content as an opaque implementation detail and not rely on
its specific format.
2. User code obtains the cookie from the response initial metadata. The client
application is responsible for managing and storing this cookie value, for
example, by implementing a 'cookie jar'.
3. For all subsequent RPCs that belong to the same session, the client includes
the stored cookie in the request metadata (in the cookie header). It is
the client application's responsibility to manage cookie expiration
(by checking its `Max-Age` attribute) and to avoid sending expired cookies.
4. The gRPC client's load balancing logic reads the cookie and attempts to route
the RPC to the previously identified backend using the information contained
within the cookie.

### Behind the scenes

The gRPC load balancing logic will prioritize sending the request to the
backend indicated by the cookie as long as it is healthy and available according
to the xDS configuration. gRPC's load balancing logic will automatically fall
back to the configured load balancing policy (e.g., round robin) to select
a new healthy backend if the backend specified in the cookie becomes unhealthy
or unreachable. The client may receive a new session cookie (generated by
the client-side filter for that new backend) upon successful connection to a new
backend - establishing affinity to the new backend.

### Draining Backends:

When a backend needs to be taken offline, it can enter a 'draining' state,
orchestrated via the xDS control plane. The gRPC client-side load balancer will
continue to route existing sticky sessions to the draining backend, allowing
those sessions to finish gracefully. New sessions (requests without an existing
affinity cookie) will not be routed to draining backends, enabling a controlled
shutdown.

## Configuration
Stateful session affinity is configured through xDS. The key components of
the configuration are:

- HttpConnectionManager:
The `HttpConnectionManager` is a core network filter within the xDS Listener
configuration that processes HTTP/2 (and HTTP/3) traffic. It includes
a `stateful_session` HTTP filter, which is responsible for managing
the cookie handling logic for SSA.
- CookieBasedSessionState:
This configuration within the `stateful_session` filter specifies:
- The cookie name.
- The cookie TTL (time to live), which corresponds to the `Max-Age` HTTP
cookie attribute.
- `override_host_status` field within the xDS Cluster configuration:
Specifies which backend health statuses are considered valid for routing for
existing sticky sessions, even if the backend is generally marked as
unhealthy for new traffic. This is essential for enabling graceful draining,
as it allows the load balancer to continue directing already-established
sessions to a backend that is in a draining state, preventing new sessions
while allowing current ones to complete.

## xDS configuration Example
Here's an example of an LDS (Listener Discovery Service) configuration snippet.
It illustrates the HttpConnectionManager with the stateful_session HTTP filter
and its CookieBasedSessionState configuration, which are key for enabling SSA:

```protobuf
version_info: "2"
resources {
[type.googleapis.com/envoy.config.listener.v3.Listener] {
name: "server.example.com"
api_listener {
api_listener {
[type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager] {
route_config { /* Omitted for brevity */ }

http_filters {
name: "envoy.stateful_session"
typed_config {
[type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSession] {
session_state {
typed_config {
[type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState] {
cookie {
name: "grpc_session_cookie"
}
}
}
}
}
}
}

http_filters { /* Omitted for brevity */ }
}
}
}
}
}
```

## Client-Side Implementation

The gRPC client application needs to implement the following logic:

- Check for the `Set-Cookie` header, which contains the session cookie generated
by the client-side gRPC SSA filter, in the response metadata when a response
is received.
- Before sending a new RPC, check if a cookie exists for the current session.
Include the cookie in the request headers using the `Cookie` header if
it exists and if it is current considering the `Max-Age` attribute value.

## Conclusion

Stateful session affinity is a powerful feature for gRPC applications that need
to maintain session-specific state. By leveraging HTTP cookies and
the xDS protocol, it ensures that requests belonging to a given session
are consistently routed to the same backend, leading to improved performance
(e.g., reduced latency due to caching or pre-loaded state), simplified
application logic on the backend, and enhanced reliability through graceful
backend draining.