Step 1 of 5 · Reading · ~3 min
Read
Advanced Algorithms
L4 vs L7 Load Balancing
The layer at which a balancer makes its decision decides what it can know and what it can do. A layer 4 balancer sees addresses and ports. A layer 7 balancer reads the application protocol, here HTTP. In this lesson your balancer gets both brains: a connection-level one and a request-level one.
What each layer sees
L4 works on TCP or UDP connections. All it has is the connection's 5-tuple: protocol, source address and port, destination address and port. It never reads the payload, so it is fast, protocol-agnostic and can pass TLS straight through. Because a connection must stay on one backend, the choice is a pure function of the 5-tuple: hash it and take the result modulo the pool size. Every packet of a connection, and every request riding on it, goes to the same backend. Real examples are IPVS, AWS NLB, HAProxy in mode tcp and Maglev.
L7 terminates the client's connection, reads the request and decides per request. What it can route on is the whole request:
GET /api/v2/orders?id=7&limit=20 HTTP/1.1\r\n
Host: api.example.com:8443\r\n
Accept: application/json\r\n
\r\n
The request line gives the method and target; the target is a path (/api/v2/orders) plus an optional query after ? that is not part of routing. The Host header says which site the client believes it is talking to; HTTP/1.1 makes it mandatory, it is case-insensitive, and it may carry a port (api.example.com:8443, or [2001:db8::1]:8443 for an IPv6 literal).
| L4 | L7 | |
|---|---|---|
| Decision input | 5-tuple | method, host, path, headers, cookies |
| Cost | very low | parse the request, buffer, a second connection to the backend |
| Protocols | any TCP/UDP | HTTP, HTTP/2, gRPC |
| TLS | can pass through | usually terminates |
| Retries | cannot (a connection is a connection) | can retry an idempotent request |
| Multiplexed HTTP/2 or gRPC | one connection pins to one backend | per-request balancing |
| Examples | NLB, IPVS, mode tcp | NGINX, Envoy, ALB |
The L4 hash
For this exercise the 5-tuple becomes the string proto|src_ip:src_port|dst_ip:dst_port, hashed with the same 32-bit MurmurHash3 as the consistent-hashing lesson (the starter provides it), and the backend is pool[hash mod N]. Same tuple, same backend, every time. Changing the source port, which is what a new connection does, may change the backend, and that is how connections spread.
L7 routing: longest prefix, then exact host
Rules map a host pattern and a path prefix to an upstream. A rule matches a request when the path starts with the prefix and the host pattern is the request's host or the wildcard *. Among the matching rules:
- the one with the longest prefix wins, because
/api/v2/is more specific than/api/, - at equal prefix length, a rule for the exact host beats
*, - no match at all goes to the default upstream.
NGINX, Envoy and Istio follow this precedence. Defining the same host and prefix twice replaces the earlier rule.
Common mistakes
- Routing on the query string:
/admin?x=1has the path/admin, and/?next=/admin/has the path/. - Comparing the Host with its port, or case-sensitively.
API.Example.COM:8443is the hostapi.example.com. - A missing Host header (an HTTP/1.0 client): the host is empty, so only
*rules can match. - Choosing by rule order instead of by prefix length.
- Hashing only the source address at L4, which pins every connection from one NAT to one backend.
Your exercise
The starter reads the commands and gives you the hash. You write the L4 choice, the request parsing and the rule matching. POOL4 <b1> ... sets the L4 pool. L4 <proto> <src_ip> <src_port> <dst_ip> <dst_port> prints the backend, or NONE. ROUTE <host> <prefix> <upstream> adds or replaces a rule, DEFAULT <upstream> sets the fallback (initially default), and L7 followed by a raw request prints the upstream.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…