Skip to content
Lesson 9 of 17

Step 1 of 5 · Reading · ~3 min

Read

Advanced Algorithms

Sticky Sessions

Load balancing wants requests to be interchangeable; application state sometimes disagrees. A multi-part upload in progress, a shopping cart held in one process's memory, a WebSocket subscription: if the next request lands on a different backend, that state is simply gone. Session stickiness (affinity) pins a client to one backend for the life of its session. In this lesson your balancer reads a real HTTP request, finds the backend the client was pinned to, and keeps sending it there.

Three ways to stick

Cookie stickiness is the precise one. On the first response the balancer adds a cookie naming the backend it chose:

HTTP/1.1 200 OK\r\n
Set-Cookie: route=10.0.0.12:8080; Path=/; HttpOnly\r\n

The browser sends it back on every later request, and the balancer routes straight to that backend without running its algorithm:

GET /cart HTTP/1.1\r\n
Host: shop.example\r\n
Cookie: theme=dark; route=10.0.0.12:8080; lang=en\r\n
\r\n

HAProxy does this with cookie SRV insert, nginx Plus with sticky cookie, and AWS ALB with its AWSALB cookie. Source-IP hashing needs no cookie and works for plain TCP, but everyone behind one office NAT shares an address and lands together, and a pool change remaps almost everyone. Hashing a session id onto the ring from the last lesson sticks without per-client state, and only about K/N sessions move when backends change.

Reading the Cookie header

The grammar is small. A request carries zero or more Cookie header lines, each a list of name=value pairs separated by ;:

Cookie: theme=dark; route=b; lang=en
        ^pair 1     ^pair 2   ^pair 3

The details are where parsers go wrong:

  • Header names are case-insensitive. cookie:, Cookie: and COOKIE: are the same header. A different header such as X-Cookie: or Set-Cookie: is not.
  • Cookie names are case-sensitive and matched whole. xroute=b, route2=b and myroute=b are other cookies; only route counts.
  • Spaces around pairs are optional, so route=b;lang=en and route=b ; lang=en are both legal.
  • There may be several Cookie lines, and the same name may repeat. Take the first route, in the order the bytes arrived.

A request ends at the blank line after its headers. The first line is the request line (GET /cart HTTP/1.1); the header lines follow.

Stickiness is a preference, not a promise

When the pinned backend is down, the request must fall back to normal selection: pick a fresh backend, issue a fresh cookie, lose the session rather than the request. A balancer that answers 502 because the cookie names a dead server has turned an availability feature into an outage amplifier. A cookie naming a backend that no longer exists (the client kept it across a config change) is treated as no cookie at all. Two caveats remain: stickiness concentrates load, since one heavy user pins to one backend whatever the algorithm wants, and it weakens redundancy. The grown-up fix is to keep session state in Redis or a database so backends are stateless; sticky routing is what you do when you cannot.

Common mistakes

  • Sticky hits advancing the rotation. The round-robin counter moves only when a new backend is assigned. A pinned request consumed no turn.
  • Substring matching. Finding route= anywhere in the header line also matches xroute= and Set-Cookie: route=.
  • Trusting the cookie blindly. A cookie for a backend that is DOWN, or not in the pool, means "assign a new one".
  • Forgetting to re-pin. Every new assignment, including a fallback, answers with Set-Cookie.

Your exercise

The starter reads the commands, collects the header lines of each request for you, and prints your answer. You write two things: finding the pinned backend in the headers, and the choice. POOL <b1> ... (all UP, rotation counter 0) and DOWN <b> / UP <b> print OK. REQUEST is followed by a raw request up to its blank line. The answer is <backend> sticky for a pinned hit, <backend> new Set-Cookie: route=<backend>; Path=/; HttpOnly for a fresh assignment (round-robin over the UP backends in pool order, one counter that only new assignments advance), or NONE when nothing is UP.

Up nextRate LimitingAdvanced Algorithms

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…