An L4/L7 load balancer and reverse proxy with adaptive routing, circuit breaking, and hedging.
- L7 reverse proxy with header rewriting, X-Forwarded-For propagation
- L4 TCP proxy with bidirectional connection forwarding
- Routing algorithms: Round Robin, Weighted Least Response Time (adaptive), Hedged requests
- Active health checking with configurable interval and timeout
- Passive health checking: 3 consecutive 5xx marks a backend dead immediately
- Retry on failure: automatic retry on the next backend when the primary returns 5xx
- Circuit breaker per backend: three-state FSM (Closed, Open, Half-Open) prevents cascade failures
- Hedged requests: speculative execution to cut tail latency (GET/HEAD only)
- Per-IP token bucket rate limiting with configurable burst and refill rate
- Connection draining: graceful drain of in-flight requests on shutdown
- Prometheus metrics with a pre-built Grafana dashboard
- YAML configuration
make dev
This starts 3 dummy backends on :9001, :9002, :9003 and Lighthouse on :8080.
docker compose up --build
| Service | Port |
|---|---|
| Lighthouse | 8080 |
| Metrics | 9090 |
| Grafana | 3000 |
| Prometheus | 19090 |
curl http://localhost:8080/
curl http://localhost:8080/debug/stats
See lighthouse.yaml:
listen:
http: ":8080"
tcp: ":4000"
metrics: ":9090"
routing: adaptive # round_robin | adaptive | hedged
health_check:
interval: "5s"
timeout: "2s"
path: "/health"
drain_timeout: "30s"
backends:
- url: "http://backend1:9001"
- url: "http://backend2:9002"rate_limit:
enabled: true
rate: 100
burst: 200
whitelist:
- "127.0.0.1"
- "10.0.0.0/8"hedge:
enabled: true
methods: ["GET", "HEAD"]Lighthouse exposes Prometheus metrics on the configured listen.metrics port.
| Metric | Description |
|---|---|
lighthouse_requests_total |
Requests proxied, by backend and status code |
lighthouse_request_duration_seconds |
Histogram of end-to-end request latency |
lighthouse_backend_active_connections |
Current in-flight requests per backend |
lighthouse_backend_alive |
1 if backend is alive, 0 otherwise |
lighthouse_circuit_breaker_state |
0=closed, 1=open, 2=half-open |
lighthouse_rate_limited_requests_total |
Requests rejected by rate limiter |
lighthouse_hedged_requests_total |
Total hedges fired |
GET /debug/stats returns per-backend status as JSON:
[
{
"url": "http://localhost:9001",
"alive": true,
"avg_latency_ms": 42.2,
"active_conns": 3,
"circuit_state": "closed"
}
]make build
Requires Go 1.22+.
- No TLS termination
- No HTTP/2 support
- No sticky sessions or consistent hashing
- Rate limiter is per-instance (not distributed)