A load balancer, written from scratch
TCP and HTTP traffic spread across backends, in C++17 on plain POSIX sockets. This page reads live stats from the running server, pushed over Server-Sent Events the moment they change.
- Listen port
- --
- Healthy backends
- --
- Active connections
- --
- Updates received
- 0
Backends
Each server gets an HTTP HEAD every five seconds, and unhealthy ones leave the rotation until they answer again.
Waiting for data
Traffic split
Share of active connections on each backend.
Idle, no active connections right now.
Connections over time
Total active connections across all backends.
Load test
Fire concurrent HTTP requests at the load balancer and watch the traffic spread across the backends above.
The load balancer frontend
Nothing fired yet. Results land here, and the backend connection counts above move as the requests arrive.
Algorithms
Four ways to pick a backend, switchable without a restart by sending SIGHUP.
Least connections
- Best for
- Mixed workloads where some requests take much longer than others.
- Cost
- O(n) scan, atomic under a single mutex lock
- To run it
- Set
algo = lcinlb.conf, then runkill -HUP $(pgrep load_balancer).
| Listen port | -- |
| Stats port | -- |
| Thread pool | 16 workers |
| Health check | Every 5 s |
| Connection: close | Injected |
| SIGHUP reload | Algorithm and weights |
Under the hood
One process, five kinds of thread, and no third-party libraries.
Thread model
- Main thread
- accept() loop on :8080
- Worker pool (16)
- handle_client() for each connection
- Health check
- HTTP HEAD every 5 s
- Stats thread
- JSON and SSE on :8081
- SIGHUP thread
- sigwait(), then reload
Design decisions
- TOCTOU-free
- One mutex covers select and increment
- atomic<Algorithm>
- Lock-free reads in worker threads
- SO_REUSEADDR
- Instant restart after a crash
- Retry on failure
- Next healthy backend when a connect fails
- sigwait()
- Safe async signal handling
Four algorithms
Least connections, round robin, IP hash and rendezvous hashing.
Weighted backends
Per-backend traffic ratios.
Health checks
An HTTP HEAD to every backend, every 5 seconds.
Thread pool
A fixed pool of 16 workers, no unbounded spawning.
Connection cap
A hard limit per backend, skipped at capacity.
SIGHUP reload
Live config changes with zero downtime.
Stats endpoint
JSON on :8081/stats, streamed live from /stats/stream.
No libraries
Pure C++17 on POSIX sockets.