Skip to content
Lesson 12 of 17

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).

L4L7
Decision input5-tuplemethod, host, path, headers, cookies
Costvery lowparse the request, buffer, a second connection to the backend
Protocolsany TCP/UDPHTTP, HTTP/2, gRPC
TLScan pass throughusually terminates
Retriescannot (a connection is a connection)can retry an idempotent request
Multiplexed HTTP/2 or gRPCone connection pins to one backendper-request balancing
ExamplesNLB, IPVS, mode tcpNGINX, 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:

  1. the one with the longest prefix wins, because /api/v2/ is more specific than /api/,
  2. at equal prefix length, a rule for the exact host beats *,
  3. 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=1 has the path /admin, and /?next=/admin/ has the path /.
  • Comparing the Host with its port, or case-sensitively. API.Example.COM:8443 is the host api.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.

Up nextTLS TerminationProduction Concerns

Discussion

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

Sign in to post a comment or reply.

Loading…