Skip to content
[menu][close]

FOUNDRYNETNo. 001SEPTEMBER 2026LOAD BALANCING

Original page: foundrynet.com/solutions/appNotes/PDFs/SessionPersist.pdf (ServerIron session persistence application note, around 2002)

Session Persistence on a Load Balancer: Sticky Session Methods

Persistence, or sticky sessions, makes a load balancer send a returning client to the same real server it used before, because the application keeps state there.

On this page

01 Why stateful applications need persistence

A load balancer chooses a server per new connection, and a web session is many connections. If the shopping cart lives in the memory of the server that handled request one, request two must reach the same server or the state is gone. Persistence guarantees that. It is a workaround; the section on statelessness below is the real fix.

02 Source IP persistence and where it fails

The balancer keeps a table of client IP to real server and consults it before the selection method. It works at Layer 4, needs no application change and costs almost nothing. It fails in two directions. Behind carrier NAT, corporate proxies or campus gateways, thousands of users share one address and all land on one server. Mobile clients change address mid-session and lose their server. Use source IP only for non-HTTP protocols where nothing better exists.

For HTTP the balancer can use cookies, which identify a browser rather than an address.

Cookie-based persistence methods. Insert is the usual default for web applications.
MethodWho sets the cookieBalancer actionTrade-off
Cookie insertThe balancerAdds a cookie naming the chosen server on the first response; reads it afterwardsNo application change; needs Layer 7
Cookie passiveThe applicationLearns an existing application cookie and maps it to the server that issued itNo extra cookie; table entry per session
Cookie hashThe applicationHashes an existing cookie value to pick a server deterministicallyNo table; a pool change reshuffles some clients
Cookie insert persistenceCOOKIE INSERT PERSISTENCE01Firstrequest, nocookie02Balancerpicks server03Response +Set-Cookie04Next requestcarriescookie05Balancerreads it,same serverCookie insert persistenceCOOKIE INSERT PERSISTENCE01First request, no cookie02Balancer picks server03Response + Set-Cookie04Next request carries cookie05Balancer reads it, same server
No table needed: the server identity travels in the cookie.

Obscure the server identifier in an inserted cookie; a plain internal address is an information leak. Mark it HttpOnly and Secure. Cookie methods need the balancer to see HTTP, which means Layer 7 processing and, for HTTPS, TLS termination.

04 Session persistence worked example: cookie insert across two virtual ports

Illustrative values. VIP 192.0.2.20 serves TCP 80 and 443 for a shop whose cart lives in server memory. The application session expires after 20 minutes idle, so the persistence timeout is 30 minutes. The inserted cookie SRV carries an opaque token rather than an address and is marked Secure and HttpOnly. Both virtual ports share one persistence group, so a client that arrives on 80 and is redirected to 443 still reaches the same real server.

Illustrative first and second responses seen by the client
$ curl -sk -D - -o /dev/null https://192.0.2.20/cart
HTTP/1.1 200 OK
Set-Cookie: SRV=a1f9c0; Path=/; Secure; HttpOnly; Max-Age=1800
X-Served-By: web2
$ curl -sk -D - -o /dev/null -H 'Cookie: SRV=a1f9c0' https://192.0.2.20/cart
X-Served-By: web2
lb1# show server persistence cookie SRV
token a1f9c0  real web2  idle 00:00:04  expires 00:29:56

The token maps to web2 in the balancer's table or, in the stateless variant, encodes web2 under a key only the balancer holds. Cookie Max-Age and table timeout are both 30 minutes so browser and balancer forget together. When web2 fails its check the entry is invalidated, the next request is balanced afresh and the cart is gone; the application shows an empty cart rather than an error, which is the documented fallback.

05 Persistence methods compared

Every method trades layer, visibility and state against the client behaviours it survives.
MethodLayerTLS passthroughSurvives shared NATSurvives address changeBalancer state
Source IP4YesNoNoTable
Cookie insert7NoYesYesNone (token) or table
Cookie passive or hash7NoYesYesTable or none
SSL session ID4TLS 1.2 and older onlyYesYesTable
URL parameter7NoYesYesTable or none

06 SSL session ID persistence and why TLS 1.3 broke it

Balancers once persisted encrypted traffic without decrypting it. Under SSLv3 and TLS 1.0 through 1.2 the client sends a session ID in the clear during the handshake and reuses it on resumption, so a Layer 4 balancer could key its table on that value. Session tickets (RFC 5077) had already weakened it. TLS 1.3 (RFC 8446) removed the mechanism. Resumption now uses pre-shared keys in tickets that are opaque, encrypted and ideally single-use, so nothing stable is visible in the path. Treat it as legacy; the replacements are TLS termination plus cookie persistence, or a stateless back end.

07 URL and parameter persistence

Some applications carry a session identifier in the URL, such as a ;jsessionid= path parameter or a query string token, for clients that refuse cookies. The balancer reads the token and maps it to a server by table (learned from the issuing server) or by hash. It requires Layer 7 inspection; the first request carries no token and falls through to the normal method.

08 Timeouts, and persistence versus true statelessness

Table-based methods need an idle timeout so entries expire. Set it slightly longer than the application session timeout; shorter, and a user returning after a break lands on a server that never met them; much longer, and the table fills with dead entries.

The clean alternative removes the need. Put session state in a shared store (a replicated cache or database) every real server reads, or sign the state into the client token so the server holds nothing local. Then any server takes any request, persistence is off and failover is instant. Persistence is a bridge to that design, not a substitute.

WARNING

Persistence and health checks interact. When a pinned server fails the balancer must reassign the client, which the application sees as a lost session. Decide in advance whether the fallback is "reassign silently" or "return an error", and test it.

09 Testing persistence

Verify with a client that stores cookies and repeats requests, with each real server returning its identity in a response header for the test.

Illustrative persistence test from a shell
curl -s -c jar.txt -b jar.txt -D - https://www.example.com/ -o /dev/null | grep -i x-served-by
curl -s -c jar.txt -b jar.txt -D - https://www.example.com/ -o /dev/null | grep -i x-served-by
# repeat; expect the same server
rm jar.txt   # fresh client; expect the pool to rotate again

Three calls with one cookie jar should name the same server; a fresh jar may land elsewhere. Repeat from a second source address to prove the pin is per cookie, not per IP. Then stop the pinned server and confirm the documented fallback. In multi-site designs, GSLB adds a second layer of stickiness at the DNS level. Persistence is one piece of the design covered in the load balancing section, and it interacts with per-crawler request limits on the VIP: a client pinned to one real server also concentrates its whole request budget on that server.

10 Failure modes and pitfalls

  • Unsynchronised tables across a pair. Table-based methods lose every pin at failover unless the table is replicated with the flow table. Token-in-cookie methods survive because the mapping travels with the client.
  • HTTP/2 connection reuse. Under RFC 9113 a browser multiplexes many requests on one connection and may reuse it for several hostnames sharing an address and certificate. A Layer 4 device pins the whole connection; a Layer 7 device must apply persistence per request.
  • Clients that never return cookies. Scripted fetchers discard cookies, so each request earns a fresh table entry that is never used again. Let such clients rotate, using the signals that mark a client as scripted to identify them.

11 Expert tips

  • Prefer a token that encodes the server under a balancer-held key over a lookup table; it needs no replication and cannot be exhausted.
  • Group every virtual port of one application into one persistence scope, so a redirect from 80 to 443 stays on the same real server.
  • Test in a 2 by 2 grid of two source addresses and two cookie jars; only the same jar should share a server.

Session persistence is the right tool while the application keeps state in memory and the wrong tool the day it stops. Until then, pair the table timeout with the application's own, group the ports, and know what the pair does with its pins when the VIP moves between paired units.

Inference servers have a modern equivalent of persistence, prefix affinity, covered in what changes when balancing model inference.

12 Questions

What is the difference between persistence and affinity?

Nothing in practice. Persistence, affinity, stickiness and sticky sessions all describe a rule that returns a client to the real server it used before. Vendors pick different words; the mechanisms are the same.

Why does source IP persistence overload one server?

Because many users can share one public address through NAT or a proxy. The balancer sees a single client and pins all of them to one server. Cookie-based methods identify each browser individually and avoid the problem for HTTP.

Does TLS 1.3 really prevent SSL session ID persistence?

Yes. TLS 1.3 removed session ID resumption and uses encrypted, ideally single-use pre-shared key tickets. A device without the key sees no stable value to persist on. Terminate TLS on the balancer and use cookies, or make the back end stateless.

How long should a persistence timeout be?

Slightly longer than the application session timeout, so a user who returns before the application logs them out still reaches the server holding their state. Far longer values waste table capacity and let the pool become unbalanced as entries linger.

Is persistence needed if sessions are in a shared store?

No. If every real server can read the session from a shared cache or database, or the state is carried in a signed client token, any server can answer any request. Disable persistence; failover loses nothing because no server holds unique state.

Should persistence cover port 80 and port 443 together?

Yes, when both ports serve one application. Group the virtual ports so the balancer keys the pin on the client rather than on the port; otherwise a user redirected from HTTP to HTTPS lands on a different real server and loses the cart or login the first server held.