Session persistence, also known as sticky sessions, is a load balancing technique used by proxies to ensure that all requests from a specific client are consistently routed to the same backend server throughout the duration of their session.
This mechanism addresses the challenge posed by stateful applications in a load-balanced environment. Many web applications maintain session-specific data (e.g., shopping cart contents, user authentication status, personalized settings) on the server. Without session persistence, a client's subsequent request might be directed to a different backend server by the load balancer. If that server does not hold the client's session data, the session state is lost, leading to errors, requiring re-authentication, or forcing the client to restart their interaction. Sticky sessions prevent this by "sticking" a client to a particular server once an initial connection is established.
How Session Persistence Works
Proxies implement session persistence using various methods, primarily by identifying a client and then mapping that client to a specific backend server.
Client Identification Methods
IP Hash (Source IP Hashing)
This method uses the client's IP address as a key to determine the backend server. The proxy hashes the client's IP address and uses the resulting value to select a server from the available pool. This ensures that all requests originating from the same IP address are directed to the same server.
- Mechanism:
hash(client_ip) % number_of_servers - Pros: Simple to implement, no client-side cookie or application modification required.
- Cons:
- Load Imbalance: If many clients share the same public IP (e.g., behind a NAT gateway, corporate network), that single server can become overloaded.
- Server Failure: If the assigned server fails, the client's session is lost, and subsequent requests will be routed to a new server (potentially losing stickiness if the hash calculation points to a different server or the proxy re-evaluates).
- Dynamic IPs: Clients with dynamic IP addresses may lose their session if their IP changes mid-session.
Cookie-Based Persistence
This is a widely used and more flexible method. The proxy or the application inserts a cookie into the client's browser. This cookie contains information used by the proxy to route subsequent requests to the correct backend server.
Proxy-Generated Cookies
The proxy itself injects a cookie into the HTTP response before sending it to the client. This cookie typically contains an identifier for the backend server that processed the initial request. On subsequent requests, the proxy reads this cookie and directs the client to the identified server.
- Mechanism: Proxy intercepts response, adds
Set-Cookie: PROXY_SESSION_ID=server_idheader. On subsequent requests, proxy readsCookie: PROXY_SESSION_ID=server_idand forwards toserver_id. - Pros: Requires no application modification, transparent to the application.
- Cons:
- Server Failure: If the identified server fails, the client's session is lost. The proxy must then route the request to a new server and update the cookie, or the client experiences an error.
- Cookie Management: Requires client browsers to accept and send cookies.
Application-Generated Cookies
The backend application itself creates and manages a session cookie (e.g., JSESSIONID for Java applications, PHPSESSID for PHP). The proxy is configured to inspect this specific application cookie and use its value (or a part of it) to determine the target backend server. The proxy might hash the cookie value or extract a server identifier embedded within it.
- Mechanism: Application sets
Set-Cookie: APP_SESSION_ID=unique_session_id. Proxy readsCookie: APP_SESSION_ID=unique_session_idand uses this value to map to a server. - Pros: Leverages existing application session management, potentially more robust in identifying unique sessions.
- Cons: Requires proxy configuration to understand application-specific cookie formats. Server failure leads to session loss.
Header-Based Persistence
Less common than IP hash or cookie-based methods, this approach uses a custom HTTP header to carry session or server identification information. The client or an intermediate proxy might insert this header.
- Mechanism: Proxy reads
X-Server-ID: server_123orX-Client-Session: abcdefand routes accordingly. - Pros: Can be useful in specific API gateway or microservices architectures.
- Cons: Requires specific client or upstream proxy cooperation to inject headers. Not suitable for standard web browsers without client-side scripting.
Comparison of Sticky Session Methods
| Feature | IP Hash | Proxy-Generated Cookie | Application-Generated Cookie |
|---|---|---|---|
| Client ID Source | Client IP Address | Proxy-injected cookie | Application-generated cookie |
| App Modification | None | None | None (proxy reads existing app cookie) |
| Load Distribution | Can be uneven (NAT/proxies) | Generally good | Generally good |
| Server Failure | Session lost, re-routes to new server | Session lost, re-routes to new server | Session lost, re-routes to new server |
| Persistence Granularity | Per IP address | Per browser session (cookie expiry) | Per application session (cookie expiry) |
| Client Requirement | None | Supports cookies | Supports cookies |
| Complexity | Low | Medium (cookie management by proxy) | Medium (proxy config to read app cookie) |
Why Session Persistence is Important
- Stateful Application Support: Essential for applications that store session data locally on the server (e.g., e-commerce carts, login sessions, multi-step forms).
- User Experience: Prevents session loss, re-logins, or loss of progress, leading to a smoother user experience.
- Application Design Simplicity: Reduces the need for complex distributed session management solutions (e.g., external session stores like Redis or Memcached), allowing applications to remain simpler.
Drawbacks and Considerations
- Load Imbalance: The primary drawback. If one server handles a disproportionately high number of "sticky" clients, it can become overloaded while other servers remain underutilized. This can negate the benefits of load balancing.
- Server Failure Impact: If a server with active sticky sessions fails, all clients currently "stuck" to that server will lose their session data. This can lead to a degraded user experience or service interruption for those clients.
- Scalability Challenges: Can complicate horizontal scaling. Adding or removing backend servers can disrupt existing sticky sessions, requiring careful management during scaling operations.
- Resource Consumption: Maintaining the stickiness mapping (e.g., in a lookup table) consumes resources on the proxy.
- Cookie Management Overhead: For cookie-based methods, there is a small overhead in setting and reading cookies for every request.
Configuration Examples
Nginx (Open Source)
Nginx can implement sticky sessions using the ip_hash directive or more advanced cookie-based methods with commercial modules or third-party modules like nginx-sticky-module-ng.
IP Hash
http {
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
In this example, ip_hash; ensures that requests from the same client IP address are consistently routed to the same server in the backend upstream group.
Cookie-Based (using sticky module - typically Nginx Plus or third-party)
If using Nginx Plus or a compatible third-party module:
http {
upstream backend {
# Using a proxy-generated cookie named "route"
# The value is a route ID assigned by Nginx to the server.
sticky route $cookie_route;
server backend1.example.com route=A;
server backend2.example.com route=B;
server backend3.example.com route=C;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
Here, sticky route $cookie_route; configures Nginx to use a cookie named route for session persistence. Nginx will set this cookie with a value (A, B, or C) corresponding to the initially chosen backend server.
Alternatively, sticky learn can be used to learn application-generated cookies:
http {
upstream backend {
# Learn from the application's JSESSIONID cookie
sticky learn
create=$upstream_cookie_JSESSIONID
lookup=$cookie_JSESSIONID
zone=client_sessions:1m; # Shared memory zone for session data
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
This configuration attempts to learn the JSESSIONID cookie set by the backend application. If the cookie is present, Nginx uses its value to route subsequent requests to the server that initially set it.
HAProxy
HAProxy offers robust sticky session capabilities, supporting both IP-based and cookie-based methods.
IP Hash (Source IP Hashing)
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance source # Uses client's IP address
server backend1 192.168.1.10:80 check
server backend2 192.168.1.11:80 check
server backend3 192.168.1.12:80 check
The balance source directive instructs HAProxy to use the client's source IP address for load balancing, effectively providing sticky sessions.
Proxy-Generated Cookie
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
cookie SERVERID insert indirect nocache # Insert a cookie named SERVERID
server backend1 192.168.1.10:80 cookie S1 check
server backend2 192.168.1.11:80 cookie S2 check
server backend3 192.168.1.12:80 cookie S3 check
Here, cookie SERVERID insert indirect nocache tells HAProxy to insert a cookie named SERVERID into the client's response. The cookie S1, cookie S2, etc., on each server line specify the value HAProxy should use for that server. HAProxy will then use this cookie to route subsequent requests. indirect means the cookie is only set if the client doesn't already have one, and nocache prevents caching proxies from caching responses with the Set-Cookie header.
Application-Generated Cookie
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
appsession JSESSIONID len 52 timeout 3h # Use the JSESSIONID cookie
server backend1 192.168.1.10:80 check
server backend2 192.168.1.11:80 check
server backend3 192.168.1.12:80 check
The appsession JSESSIONID len 52 timeout 3h directive configures HAProxy to look for a cookie named JSESSIONID (common for Java applications). len 52 specifies the length of the session ID to consider, and timeout 3h sets how long HAProxy will remember the session-to-server mapping if the cookie isn't present in a request. This method requires the application to set the JSESSIONID cookie.