Feb 5, 2025

Sticky Sessions, Session affinity & Session persistence

First of all, all these three terms in title are same and used interchangeably.

Sticky sessions or session affinity is technique used in load balancers. Its used by load balancers to ensure that all requests for a given session from a particular user always go to the same server.

Once a client establishes a connection with a particular server, the load balancer remembers this mapping and directs all subsequent requests from that client to the same server.

Here's a quick illustration -

image credit

Why connect a client to same server ?

In distributed systems, we try to connect a client to same server for three reasons.

  1. Performance

We dont need to remember and transfer the sessions. This saves time and bandwidth.

  1. Caching efficieny

Allows servers to maintain local caches of user data, improving response times.

  1. Session state preservation

Without sticky sessions, the server may not have all the necessary information to handle the user's session correctly. This is critical for applications that rely on session state, such as shopping carts or user authentication. E.g Without sticky sessions: User adds items to cart on Server A, but next request goes to Server B where cart appears empty.

How sticky sessions are implemented ?

There are different ways in which load balancers implement sticky sessions. Lets discuss them one by one.

  1. Cookie based stickiness

In this approach, the load balancer add a unique set-cookie header to the response sent to the client for the first request. This cookie contains information about the server to which the client should be directed for subsequent requests.

The cookie added can be either load balancer specific or application specific.

Application specific cookie

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: JSESSIONID=abcdef12345; Path=/
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: JSESSIONID=abcdef12345; Path=/

Load balancer specific cookie

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: AWSELB=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Path=/
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: AWSELB=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Path=/

The client's browser then sends the cookie in subsequent requests, allowing the load balancer to direct the request to the appropriate server.

GET /somepage HTTP/1.1
Host: example.com
Cookie: JSESSIONID=abcdef12345
GET /somepage HTTP/1.1
Host: example.com
Cookie: JSESSIONID=abcdef12345

or

GET /somepage HTTP/1.1
Host: example.com
Cookie: AWSELB=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GET /somepage HTTP/1.1
Host: example.com
Cookie: AWSELB=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  1. IP based stickiness

In this approach, the load balancer uses clients IP address and keep a mapping table to direct the request to the same server. This approach does not work for clients using dynamic IP addresses or clients behind NAT.

  1. URL based stickiness

In this approach, the application embedds the session id in the url. The load balancer uses a parsing logic to extract this session id and direct the request to the same server.

Configuring sticky sessions

In this section we will discuss how to configure sticky sessions in different load balancers.

  1. NGINX

The sticky; directive within the upstream block enables the default cookie-based sticky sessions using the ngx_http_upstream_module. By default, it uses the route method, which inserts a cookie named ROUTEID.

upstream backend {
sticky cookie srv_id expires=1h; # Cookie-based affinity
server 10.0.0.1;
server 10.0.0.2;
}
upstream backend {
sticky cookie srv_id expires=1h; # Cookie-based affinity
server 10.0.0.1;
server 10.0.0.2;
}

For open-source Nginx, you can achieve IP-based stickiness using the ip_hash directive:

upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
  1. AWS Elastic Load Balancer

You can configure sticky sessions for a Classic Load Balancer through the AWS Management Console or the AWS CLI.

Using the load balancer generated cookie

aws elb enable-availability-zones-for-load-balancer --load-balancer-name my-loadbalancer --availability-zones us-west-2a us-west-2b

aws elb create-lb-cookie-stickiness-policy --load-balancer-name my-loadbalancer --policy-name my-stickiness-policy --cookie-expiration-period 3600

aws elb set-load-balancer-policies-of-listener --load-balancer-name my-loadbalancer --load-balancer-port 80 --policy-names my-stickiness-policy
aws elb enable-availability-zones-for-load-balancer --load-balancer-name my-loadbalancer --availability-zones us-west-2a us-west-2b

aws elb create-lb-cookie-stickiness-policy --load-balancer-name my-loadbalancer --policy-name my-stickiness-policy --cookie-expiration-period 3600

aws elb set-load-balancer-policies-of-listener --load-balancer-name my-loadbalancer --load-balancer-port 80 --policy-names my-stickiness-policy

Using the application generated cookie

aws elb create-app-cookie-stickiness-policy --load-balancer-name my-loadbalancer --policy-name my-app-stickiness-policy --cookie-name JSESSIONID

aws elb set-load-balancer-policies-of-listener --load-balancer-name my-loadbalancer --load-balancer-port 80 --policy-names my-app-stickiness-policy
aws elb create-app-cookie-stickiness-policy --load-balancer-name my-loadbalancer --policy-name my-app-stickiness-policy --cookie-name JSESSIONID

aws elb set-load-balancer-policies-of-listener --load-balancer-name my-loadbalancer --load-balancer-port 80 --policy-names my-app-stickiness-policy
  1. HAProxy
backend myapp
balance roundrobin
cookie SERVERID insert nocache # Cookie-based stickiness
server s1 10.0.0.1:80 cookie s1
server s2 10.0.0.2:80 cookie s2
backend myapp
balance roundrobin
cookie SERVERID insert nocache # Cookie-based stickiness
server s1 10.0.0.1:80 cookie s1
server s2 10.0.0.2:80 cookie s2

Drawbacks of sticky sessions

  1. Uneven load distribution

Sticky sessions can lead to uneven load distribution across servers. This can be a result of user hotspots where we have a small number of users generating large number of requests.

Hotspot issue essentially negates the benefits of load balancing.

  1. Single point of Failures

If a backend server handling sticky sessions fails, all sessions tied to that server will be lost, leading to a poor user experience (e.g., loss of shopping cart data, being logged out).

This reduces the overall fault tolerance of the system.

We need to employ session replication to mitigate this issue. This is done by maintaining a copy of the session data in distributed caches or database.

  1. Scaling issues

Scaling out the backend tier can be complicated with sticky sessions. Adding new servers won't automatically balance existing sessions. Newly added servers will only handle new sessions.

  1. Client side dependencies

Cookie-based stickiness relies on the client's browser accepting and sending cookies. If a user disables cookies, stickiness will be lost.

This makes the system vulnerable to client-side configuration changes.