zerohop.dev
ProThis module is part of zerohop Pro.

HAProxy Load Balancing

Five things every engineer 'knows' about load balancing, and what HAProxy 3.4 actually does. leastconn is a misnomer: the tree it walks is ordered by a single precomputed integer per server — in-flight requests plus queue length, plus one, scaled by the effective-weight ceiling and divided by the server's own weight — so it orders on load PER UNIT OF WEIGHT, a server of twice the weight keeps being chosen until it holds roughly twice the work, and an idle server keys to zero and sorts unambiguously first. Round-robin does not simply 'ignore load' either: the rotation equalises the ARRIVAL RATE rather than occupancy, so a backend answering more slowly runs hotter at the same arrival rate and reaches its own limit first — at which point it is SKIPPED, not overloaded, because the rotation only returns a server that has no queue and is below its dynamic maxconn. A failing health check does not mark a server down: it decrements a counter that begins at rise + fall - 1 and snaps to zero only once it drops below rise, so a broken backend keeps taking requests for the interval times the fall count, plus however long the failing check takes to time out — and the spacing of those checks is re-decided on every one of them from the health state, which is why the arithmetic only holds while fastinter is unset. The seam that actually decides what your controls do is dynamic versus static: source and uri hashing resolve by default through a map of the usable servers, which carries no dynamic flag, so a runtime weight change is refused outright and the slowstart weight ramp is skipped entirely — while the same slowstart still ramps the server's admission limit, because that ramp needs only a maxconn. A restarting backend therefore takes its full share of hashed keys at once against a fraction of the limit, and the excess queues. There are two limits called maxconn and they fail differently: the frontend one caps what is accepted, the server one queues the overflow inside HAProxy with a wait you can measure, and it becomes a 503 only past `timeout queue` — unset, the request just waits. What that limit counts is sessions, not sockets, which is why moving a backend to HTTP/2 collapses the connection count without admitting a single extra concurrent request. And a stick table is not a connection tracker: it keys on whatever sample expression the configuration names, and the entry stores the server by its persistent id — so it survives a rebalance that moves every hash key, while a table at its size limit spares its busy entries and fails the ARRIVING client's insert instead. Change the backend count, balance algorithm, health-check interval, server maxconn, failure count, stick-table persistence, slowstart ramp and content-switching rule, and watch the server-computed cascade across all five layers — selection, health checking, connection limits, stick tables and ACL routing — including the conjunctions where two settings that are each survivable alone are not survivable together, such as routing on the client address while also hashing on it. Validated against HAProxy v3.4.6 source (assign_server, fwlc_get_key, fwlc_get_next_server, get_server_sh, map_get_server_hash, lb_map_ops, lb_chash_ops, check_notify_failure, process_chk_conn, srv_set_stopped, srv_getinter, server_recalc_eweight, srv_dynamic_maxconn, pendconn_add, stktable_fetch_key, stktable_get_entry, stktable_trash_oldest, stksess_new, acl_exec_cond).

  • All current + future modules
  • Full kata library
  • Progress dashboard + weak area analysis

Cancel anytime. Billed annually.

zerohop.dev — Interactive Network Protocol Simulators