Kahibaro
Discord Login Register

Session persistence

Why Session Persistence Matters in Load Balancing

Session persistence (also called “sticky sessions”) is about making sure that a user keeps hitting the same backend server across multiple requests, instead of being freely bounced between nodes by the load balancer.

At HTTP level, most applications maintain “session state” in memory or on local disk (for example, login status, cart contents, wizard steps). If the next request is routed to a different backend that doesn’t know that state, you see:

Session persistence is a workaround to keep a stateful app working behind a load balancer, by tying a client to a specific backend server for some period of time.

It’s not the same as:

Those are longer‑term, more scalable solutions. Session persistence is a simpler, infrastructure‑side solution, but it has trade‑offs.

Key Concepts and Trade‑offs

Stickiness duration

Persistence doesn’t usually last forever. Common timeframes:

Important points:

Granularity of affinity

What is “stuck” to what:

The more tightly you bind, the more you risk uneven workloads if clients are not evenly distributed.

Impact on load distribution

Session persistence restricts the load balancer’s freedom to pick the best server on each request:

In multi‑LB setups (e.g., anycast, multiple HAProxy instances), you must ensure that all LBs share enough information (or use a scheme that doesn’t require sharing) for persistence to work correctly.

Common Strategies for Session Persistence

1. Source IP–based persistence

The simplest technique: the load balancer chooses a backend based on the client IP address and keeps using that mapping.

How it typically works

Conceptually:

$$
\text{backend} = \text{hash}(\text{client\_ip}) \mod N
$$

where $N$ is the number of backends.

Advantages

Limitations

When to use

2. Cookie‑based persistence

For HTTP/HTTPS, cookies are the most common and flexible form of stickiness.

Two main patterns:

LB‑generated cookie

Flow:

  1. First request: LB picks a backend (via its normal algorithm, e.g., round‑robin).
  2. LB adds a cookie to the HTTP response, e.g. Set-Cookie: SRV_ID=backend3; Path=/; HttpOnly.
  3. Client sends that cookie on future requests.
  4. LB reads SRV_ID and routes to the corresponding backend.

Properties:

You typically configure:

App‑generated cookie (routing based on app session ID)

Sometimes the app already has a cookie that uniquely identifies the session, such as JSESSIONID, PHPSESSID, or a custom ID. The LB can:

  1. Extract the session ID from the cookie.
  2. Hash the ID to select a backend.
  3. Optionally cache the mapping in a stick table.

This lets the app own the cookie semantics while the LB provides consistent routing.

Advantages:

Caveats:

Failure scenarios and behavior

You must decide what happens if:

Typical options:

From the user’s perspective, failing over may:

You should test failure behavior explicitly.

3. URL parameter–based persistence

In some legacy or special cases, the session ID lives in the URL (e.g., ;jsessionid=... or ?session_id=...). The LB can:

This is less common today due to:

Use only if cookies are not an option and you fully understand the risks.

4. SSL/TLS session and connection‑based stickiness

For HTTPS, if the LB terminates TLS, you’re back to HTTP cookies/IP/etc. If it doesn’t terminate (TCP pass‑through), you have fewer tools:

In long‑lived connections (websockets, HTTP/2 multiplexed over a single TCP connection), the connection itself is the unit of stickiness.

Implementation Patterns in Practice

This section focuses on design choices rather than configs for specific software (those are covered in the Apache/Nginx/HAProxy chapters).

Combining persistence with load‑balancing algorithms

Persistence sits “on top of” your base algorithm:

  1. For a request without an existing stick key:
    • Use the base algorithm (round‑robin, least‑connections, etc.).
    • Assign a stick key (cookie, IP, session hash).
  2. For subsequent requests with a stick key:
    • Route directly to the associated backend, bypassing algorithm choice.

As a result:

For highly stateful apps, “least connections” matters less once stickiness is in place. For very short sessions or many anonymous requests (static content), persistence may not be necessary and can be disabled.

Persistence and high availability

Multi‑node LB setups introduce questions:

Options:

  1. Shared state (e.g., stick tables replicated between HAProxy nodes)
    • More complex to configure.
    • Supports true failover mid‑session if the first LB crashes.
  2. Stateless deterministic mapping (hashing a session ID or IP)
    • No shared state needed.
    • Works well if you keep the backend set stable or use consistent hashing.

For active‑passive LB pairs (VRRP, keepalived, etc.), a simple approach is:

For active‑active setups (BGP, anycast), you typically need either:

Session persistence and scaling

Persistence interacts with scaling in several ways:

Operational patterns:

Session persistence and microservices / APIs

Many APIs and microservices aim to be stateless. In that case, you often:

Cases where persistence is still useful in service architectures:

Evaluate:

When you can, dropping persistence simplifies ops and scaling enormously.

Security and Privacy Considerations

Cookie attributes

For LB‑managed cookies:

Example attributes:

(Exact syntax varies; see your load balancer docs.)

Information leakage

Don’t expose internal topology or server names in:

Instead of SRV_ID=backend1.example.internal, prefer an opaque ID or hash that only the LB can interpret.

Predictable stickiness and abuse

Attackers may exploit persistence for:

Mitigations:

Observability and Troubleshooting

What to log

To debug and monitor session persistence, capture:

For HTTP logs, you might add fields like:

Common issues and how to reason about them

Users randomly logged out or losing carts

Uneven load despite round‑robin configuration

You might:

Issues during deployments

You should integrate:

Designing a Strategy for a Real Application

When deciding on a session persistence strategy, answer these questions:

  1. How does the application manage state?
    • In‑process memory, local disk, external DB/cache, tokens, etc.
  2. Can the app be made stateless (or “less stateful”)?
    • Sometimes moving just login state out of memory avoids the need for persistence for most endpoints.
  3. What is the typical session lifetime and workflow?
    • Short, bursty interactions vs long‑running sessions.
  4. What are the client patterns?
    • Many NAT users, mobile networks, internal LAN, mix?
  5. How critical is perfect session continuity?
    • Is it acceptable that on rare failure events users must re‑login?

Then choose:

Finally:

This chapter’s goal is to help you recognize when and how to apply session persistence in load‑balanced environments, and what operational and architectural consequences that choice brings.

Views: 23

Comments

Please login to add a comment.

Don't have an account? Register now!