Sticky session

On this page 7

A sticky session, also called session affinity or session persistence, is a load balancing behavior that routes every request from one client to the same backend server for the duration of a session. In load balancing, it exists to serve applications that keep user state in server memory, such as a shopping cart or login session.

Stickiness overrides the normal distribution algorithm only for clients that already have a session. New clients are still placed by the configured method, for example round robin or least connections, and are then pinned to the chosen server.

How a sticky session binds a client to a server

A sticky session works by giving the load balancer a key that identifies the client and a mapping from that key to a backend. On the first request, the balancer chooses a server normally and records the choice. On every later request, it reads the key, looks up the mapping and bypasses the balancing algorithm as long as the server is healthy.

The key can live in the client, usually as a cookie, or in a table on the load balancer, keyed by source address or another attribute. The method chosen determines how stickiness behaves behind NAT, across balancer restarts and when servers are added.

MethodHow the key is storedStrengthWeakness
Balancer-inserted cookieCookie set by the load balancerPrecise per browser, no shared table neededRequires HTTP and visibility into encrypted traffic
Application cookieExisting session cookie such as a session IDFollows the real application sessionBalancer must learn and track the value
Source IP affinityHash or table of client addressesWorks for any TCP or UDP protocolMany users behind one NAT land on one server
Consistent hashing on a headerHash of a header or URL parameterNo state on the balancerRebalances part of the clients when servers change
Methods for implementing session affinity

Key parameters of session persistence

Session persistence is controlled by a small set of parameters that decide how long a binding lasts and what happens when the bound server becomes unavailable.

ParameterTypical rangeEffect
Affinity timeoutMinutes to hours, often matching the application sessionHow long an idle binding is kept
Cookie lifetimeSession cookie or fixed durationWhether stickiness survives a browser restart
Failover behaviorRebind or rejectWhat happens when the bound server fails a health check
Draining periodSeconds to tens of minutesTime existing sessions keep using a server being removed
Source mask for IP affinity/32 to /24How coarsely client addresses are grouped
Parameters that shape sticky behavior

Connection draining is the parameter most often overlooked. Without it, removing a server for maintenance immediately breaks every session pinned to it, while a draining period lets those sessions finish and stops new bindings to that server.

Sticky sessions compared with stateless designs

Sticky sessions are a workaround for server-side state, and the alternative is to move that state out of the web server. The comparison shows why modern architectures usually prefer stateless servers.

ApproachWhere state livesServer failure impactLoad distribution
Sticky sessionMemory of one serverUsers on that server lose their sessionCan become uneven
Shared session storeRedis, Memcached or a databaseOther servers continue the sessionEven
Client-side tokenSigned cookie or tokenNo session lossEven
Session replicationCopied between serversPeer holds a copyEven, with replication overhead
Ways to handle session state behind a load balancer

Even with a shared store, some teams keep weak stickiness for performance, because a server that already holds a client’s cached data answers faster. In that case affinity is an optimization, not a requirement, and losing it causes no errors.

When sticky sessions are the right choice

Sticky sessions are justified when the application cannot be changed to externalize state, or when the state is expensive to rebuild. Typical cases include:

  • Legacy web applications that store sessions in local process memory.
  • WebSocket and long-polling fallbacks, where several related HTTP requests must reach the same node.
  • Stateful protocols such as some VPN or SIP deployments that rely on per-server context.
  • Local caches that are expensive to warm, where affinity raises the cache hit rate.

For new applications, the safer default is to make servers stateless and interchangeable, so that autoscaling, rolling deployments and failures do not depend on where a user happened to land.

Pitfalls of sticky sessions

The main risk of stickiness is uneven load. Long sessions accumulate on the servers that were available when traffic began, so newly added servers receive only new users and autoscaling takes effect slowly.

  • NAT hot spots: with source IP affinity, an entire corporate office may map to a single backend.
  • Session loss on failure: users bound to a failed server are logged out unless state is shared.
  • Deployment friction: rolling updates must wait for draining or accept broken sessions.
  • Cookie handling: affinity cookies need the Secure and HttpOnly attributes and must not expose internal server names.

Understanding it simply

Imagine a bank with several tellers. Normally each customer goes to whichever teller is free. With a sticky session, once a customer has started a transaction with one teller, that customer always returns to the same teller, because only that teller has the paperwork on the desk.

This keeps things working when the paperwork cannot be shared, but it also means some tellers get busier than others, and if one teller goes home, their customers have to start over.

Applied in practice

An online retailer runs an older shop application on four web servers behind a load balancer. The application keeps the shopping cart in server memory, so without affinity, customers saw their carts empty whenever a request landed on a different server.

The operations team enabled a balancer-inserted cookie with a 30-minute idle timeout and a five-minute draining period for deployments. Cart errors disappeared. During a sale, however, the team noticed that two newly started servers stayed almost idle while the original four ran hot, because existing shoppers stayed pinned. The long-term fix was to move carts into a shared Redis store, after which stickiness became optional and new servers took load immediately.