Reading — step 1 of 5
Read
Sticky Sessions
Load balancing wants requests to be interchangeable; application state sometimes disagrees. A multi-part file upload in progress, an in-memory shopping cart, a WebSocket subscription — if the next request lands on a different backend, that state is simply gone. Session stickiness (affinity) pins a client to a backend for the lifetime of its session.
Three mechanisms, in increasing sophistication:
Cookie-based stickiness. On the first response, the LB injects a cookie naming the chosen backend:
Set-Cookie: route=server2; Max-Age=3600
Every later request carries the cookie; the LB reads it and routes straight to server2, skipping the balancing algorithm. This is HAProxy's cookie SRV insert indirect nocache, nginx's sticky cookie, and AWS ALB's AWSALB duration-based cookie. It's precise (per-browser, not per-network) and survives pool changes.
Source-IP hashing. hash(client_ip) % N. No cookie needed, works for plain TCP — but every user behind one corporate NAT or mobile carrier gateway shares an IP and lands on the same backend, and the % N remaps almost everyone whenever the pool changes.
Consistent-hash on a session ID. Hash a session token onto the ring from last lesson: stickiness without per-client LB state, and only K/N sessions move when backends change.
The part everyone gets wrong: failure
Stickiness is a preference, not a guarantee. When the pinned backend goes down, the request must fall back to normal selection — pick a fresh backend, issue a new cookie, and lose the session rather than the request. An LB that returns 502 because the cookie names a dead server has turned an availability feature into an outage amplifier. Same rule for a cookie naming a backend that no longer exists (config changed, client kept the old cookie): treat it as no cookie at all.
The strategic caveats: stickiness concentrates load (one heavy user pins to one backend and the algorithm can't spread them), and it weakens redundancy (losing a backend loses its sessions). The grown-up fix is to externalize session state to Redis or a database so backends are stateless — sticky routing is what you do when you can't.
Your exercise
Implement request() in the starter's StickyRouter. Commands: POOL <b1> <b2> ..., DOWN <b> / UP <b>, and REQUEST <client_id> [cookie] where the cookie is a backend name (or absent, or -). Logic:
- If the cookie names an UP backend → print
<backend> sticky. - Otherwise round-robin among UP backends → print
<backend> new. - No UP backends at all → print
NONE.
The round-robin is the starter's _rr(): one global counter that indexes ups[rr_idx % len(ups)] and increments on every new assignment.
Grader traps, from the real tests:
- Sticky hits must NOT advance the round-robin counter. Sequence on
POOL s1 s2:REQUEST c1→s1 new,REQUEST c2→s2 new,REQUEST c3 s2→s2 sticky, thenREQUEST c4→s1 new. If the sticky hit consumed a rotation slot, c4 would gets2and fail. - Unknown cookies fall through.
REQUEST u zzon poola bprintsa new—zzisn't a backend, so it's just a new client. - Down means fall back, then re-pin. After
DOWN a,REQUEST u1 aprintsb new(not an error); afterUP a,REQUEST u1 aprintsa stickyagain. - Everything down:
REQUEST c2 xwith x and y both DOWN printsNONE— even though the cookie names a real backend.
Output format is exact: backend name, one space, sticky or new.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…