Networking admin · Part 11 of 12

Load balancing, L4 vs L7 and when each matters

May 23, 20258 min read#networking#operations#networking-admin#operations

Load balancing, L4 vs L7 and when each matters

Field note. Your panel front-door is L7. Your game traffic, when it gets load-balanced at all, is L4. The difference matters when you're picking how to scale.

Many services run on multiple servers. A load balancer is the thing that decides which incoming request goes to which server. It sounds simple. The implementation choices have meaningful consequences.

The fundamental choice: Layer 4 (TCP/UDP) or Layer 7 (HTTP). Both are legitimate. Each has costs and benefits. This article walks through them.

L4 vs L7 at a glance

L7: application-layer LB (nginx, Envoy, ALB)

HTTP request

/api/* -> backend A
/img/* -> CDN
sticky cookie -> backend B

Client

L7 LB
reads URL, headers, cookies

Backend A

Backend B

L4: transport-layer LB (HAProxy in TCP mode, AWS NLB)

TCP connection

picks backend by IP/port hash
or round-robin, passes raw TCP

Client

L4 LB

Backend N

L4 is faster and protocol-agnostic. L7 is smarter and needed when you want to route based on URL, hostname, headers, or sticky sessions.

The basic problem

You have 10 backend servers, identical, each running a copy of your service. Users connect to one IP and port. Something needs to decide which of the 10 backends each user reaches.

The "something" is the load balancer. It accepts the user's connection, picks a backend, and forwards.

Variations:

  • Round-robin (each new connection goes to the next backend in sequence).
  • Random.
  • Least-loaded (track backend load, pick least busy).
  • Hash-based (consistent hashing on client IP, so the same client always reaches the same backend).
  • Latency-aware (route to backend with best response time).

The algorithm choice matters. So does the layer.

Layer 4 load balancing

A Layer 4 load balancer operates on the TCP / UDP layer. It sees IPs and ports. It doesn't decode the application protocol.

How it works:

  1. Client connects to the load balancer's IP and port.
  2. Load balancer picks a backend, opens a TCP connection to that backend.
  3. Load balancer forwards bytes between client and backend, in both directions.
  4. Connection ends; load balancer cleans up.

The load balancer is essentially a "forwarder." It doesn't know what's in the packets.

Characteristics:

  • Fast. Minimal CPU overhead. Modern hardware can do L4 load balancing at line rate.
  • Protocol-agnostic. Works for HTTP, HTTPS, SSH, databases, anything TCP/UDP.
  • Less feature-rich. Can't make routing decisions based on URL paths or headers.
  • Cookie-stickiness not possible at the load balancer; must be done elsewhere.
  • TLS termination not at the LB. The LB sees encrypted bytes.

Common L4 LBs: HAProxy in TCP mode, LVS (Linux Virtual Server), AWS NLB (Network Load Balancer), various hardware appliances.

Layer 7 load balancing

A Layer 7 load balancer parses the application protocol (usually HTTP). It can see URLs, headers, cookies, methods.

How it works:

  1. Client connects to the LB's IP and port.
  2. LB completes the TCP handshake and (for HTTPS) the TLS handshake.
  3. LB reads the HTTP request.
  4. LB makes a routing decision based on the request (URL path, host header, cookies).
  5. LB picks a backend, opens a new connection (or reuses one), and forwards the request.
  6. LB receives the response and forwards back to the client.

The LB is now an intermediary that understands what's being asked.

Characteristics:

  • Smarter routing. Can send /api/* to one backend, /static/* to another.
  • TLS termination. LB handles encryption; backends speak plain HTTP.
  • Sticky sessions via cookies. LB can inject a cookie that pins users to a backend.
  • Per-request decisions. Each HTTP request can go to a different backend.
  • More CPU and memory overhead. LB has to parse every request.
  • Limited to HTTP-like protocols (or others the LB understands).

Common L7 LBs: nginx, HAProxy in HTTP mode, AWS ALB (Application Load Balancer), Envoy.

Choosing between them

Use L4 when:

  • Protocol isn't HTTP.
  • Pure throughput is important.
  • You want minimal LB complexity.
  • TLS termination needs to happen at backends (compliance reasons).
  • You're load-balancing across the public internet (anycast-style L4).

Use L7 when:

  • You're serving HTTP/HTTPS.
  • You want path-based routing.
  • You need TLS termination at the LB.
  • You want to do response transformations (caching, compression).
  • You need rich logging at the LB level.

Many real architectures use both: L4 at the outer edge for raw throughput and DDoS resilience, L7 deeper for application-level intelligence.

Algorithms

Within each layer, the algorithm choice matters.

Round-robin. Each new connection goes to the next backend. Simple, fair if backends are equal.

Weighted round-robin. Backends with higher weights get more connections. Useful when backends aren't identical (different sizes).

Least connections. Each new connection goes to the backend with the fewest active connections. Good for long-lived connections.

Least time. Picks the backend with the best recent response time. Adaptive.

Hash-based (consistent hashing). Client IP or session ID hashed; same hash goes to same backend. Provides stickiness without cookies. Works well when backends rarely change.

Random. Sounds bad; actually works well at scale (probabilistic balance).

For most setups, round-robin or least-connections is fine.

Sticky sessions

Some applications need a user's requests to always go to the same backend. Reasons:

  • Backend stores session state locally (not in shared cache).
  • WebSocket connections (already pinned by being TCP-level).
  • Pinned game sessions.

L4 stickiness:

  • Hash on client IP (simple, gets confused by NAT, breaks if client IP changes).
  • Session-table-based stickiness (LB remembers each connection).

L7 stickiness:

  • Cookie-based (LB injects a cookie that names the backend).
  • Header-based.

For modern web apps, the better answer is usually: store session state in shared infrastructure (Redis, etc.) so any backend can handle any user. Stickiness is a workaround for backends that don't support this.

Health checks

Critical detail: LBs need to know which backends are healthy.

The LB periodically polls each backend:

  • TCP-level: open a connection. Closed cleanly = healthy.
  • HTTP-level: GET a specific path (often /health or /ping). 200 OK = healthy.

Unhealthy backends are removed from rotation. Healthy backends are re-added.

Tuning:

  • Check frequency (every 5 seconds is typical).
  • Failure threshold (3 consecutive failures = unhealthy).
  • Recovery threshold (2 consecutive successes = healthy again).

Bad health checks cause flapping (backends alternate between healthy and unhealthy), instability, and confusion. Good health checks catch real failures without false positives.

SSL/TLS at the load balancer

For HTTPS services, the LB usually terminates TLS. Reasons:

  • Centralizes certificate management (one place to install certs).
  • Reduces backend CPU load (decryption is expensive).
  • Lets LB inspect requests (impossible if encrypted to backend).

Implications:

  • The LB has access to plaintext requests (it must, to make routing decisions).
  • Traffic from LB to backend is usually plaintext over a private network.
  • If your backend network isn't trustworthy, you can re-encrypt (LB to backend uses HTTPS too).

For most setups, plaintext between LB and backend is fine if the network is private.

A common architecture

Modern web service architecture:

                            [ DNS round-robin / anycast ]
                                       |
                            [ L4 load balancer at edge ]
                            /          |           \
                    [ L7 LB ]      [ L7 LB ]      [ L7 LB ]
                    /    \         /    \         /    \
                [ App ]  [ App ] [ App ] [ App ] [ App ] [ App ]

Layers:

  1. DNS or anycast spreads users across regions / data centers.
  2. L4 LBs handle the raw TCP at each entry point.
  3. L7 LBs do per-request routing and TLS termination.
  4. App servers do the work.

Each layer can scale independently.

Load balancing in game hosting

Most game servers don't load-balance in the traditional sense. A specific Minecraft server is one Minecraft server; you can't shard a single player's session across machines.

Where load balancing applies in gaming:

  • Login services: web-style, can be load-balanced normally.
  • Matchmaking: stateless requests that route players to game servers.
  • Web admin panels: regular web, normal load balancing.
  • Bungee/Velocity proxies in Minecraft: a player connects to a proxy, which routes them to a specific backend Minecraft server. This is application-level "routing," not classic load balancing, but the architecture is similar.

For real-time game session traffic, you typically use unicast (specific player goes to specific server, no balancing) and let DNS / region selection handle distribution.

Failure modes

A few patterns:

LB itself fails. Single point of failure if not redundant. Most production setups have multiple LBs in active-active or active-passive configuration.

Connection table exhaustion. Each LB tracks active connections in a table. If the table fills (lots of concurrent users or attacks), new connections fail. Tune table sizes; use distributed LBs if needed.

Slowloris and similar attacks. Attackers open many slow connections, hogging LB resources. Mitigations: timeouts, connection limits per client, WAF features.

Backend exhaustion. All backends become unhealthy at once. LB has nothing to route to. Graceful degradation (serve cached responses, return clear errors) matters.

When NOT to use a load balancer

For simple setups:

  • One app on one server.
  • Internal services with stable, fixed clients.
  • Quick experimental deployments.

A reverse proxy without explicit load balancing is fine. As you scale to multiple backends, add load balancing.

Don't load-balance before you need to. Premature distribution is a real form of complexity.

Conclusion

Load balancing distributes incoming traffic across multiple servers. The L4 vs L7 choice is fundamental: L4 is fast and protocol-agnostic; L7 is smart and HTTP-specific.

For most public web services, the typical pattern is L4 at the very edge for throughput, L7 deeper for routing intelligence, with health checks, TLS termination, and stickiness handled at the appropriate layer.

For game hosting, load balancing applies mostly to the web-style surfaces (login, matchmaking) rather than to the game sessions themselves.

Getting load balancing right is one of the major architectural decisions for any service that needs to scale. Now you have the vocabulary to think about it.

Coming up

The last article in Series B: the OSI model. Useful even though it's mostly wrong, because everyone in networking talks in its terms. Time to demystify.


Hosting your game server with AndroHost means we handle most of what's in this post for you automatically: tier sizing, SRV records, off-site backups, DDoS protection.

Browse plans·More posts·Discord