Resilience
Meridian provides multiple layers of resilience to protect both backends and the proxy itself from overload and failure.
Circuit Breaker
Each cluster has a circuit breaker that limits the number of concurrent requests to the backend. When the limit is exceeded, new requests are immediately rejected with 503 Service Unavailable instead of queuing and adding to backend pressure.
[clusters.circuit_breaker]
max_connections = 1024
max_pending_requests = 1024
max_requests = 1024
RAII Guards
Circuit breaker slots are managed via RAII guards. When a request acquires a slot, it receives a CbGuard. The slot is automatically released when the guard is dropped — whether the request succeeds, fails, or panics:
try_acquire() → Some(CbGuard) → request proceeds → guard drops → slot released
try_acquire() → None → 503 returned immediately
This eliminates the “forgot to release” class of bugs entirely.
Performance
Circuit breaker check: 5.3ns (single fetch_add + compare).
Token Bucket Rate Limiter
For per-route rate limiting, TokenBucket implements a classic token bucket algorithm:
- Tokens are added at a configurable rate
- Each request consumes one token
- When the bucket is empty, requests are rejected
Retry Policy
Configurable per-route retry policy:
[routes.retry_policy]
num_retries = 3
retry_on = ["503", "connect-failure"]
The retry decision is a pure function (~0.7ns) that checks the response status code against the retry-on list and the current attempt count against the maximum.
Per-IP Connection Limits
The proxy limits connections per source IP address (default: 256) to prevent a single client from exhausting connection resources. Like the circuit breaker, this uses RAII guards for automatic cleanup:
try_acquire(ip) → Some(ConnectionGuard) → connection proceeds → guard drops → slot released
try_acquire(ip) → None → connection dropped (TCP RST)
Slowloris Defense
A 60-second timeout on header reading prevents slow clients from holding connections open indefinitely. If a client doesn’t complete sending headers within the timeout, the connection is closed.
Defense Summary
| Attack | Defense | Mechanism |
|---|---|---|
| Backend overload | Circuit breaker | Max concurrent requests per cluster |
| Connection exhaustion | Per-IP limits | Max 256 connections per source IP |
| Slow headers (Slowloris) | Read timeout | 60-second header read deadline |
| Large headers | Size limit | 64KB max header size |
| Request smuggling | Strict parsing | Reject CL+TE, duplicate CL, whitespace CL |
| Path traversal | Normalization | Collapse //, resolve .. before routing |