Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

AttackDefenseMechanism
Backend overloadCircuit breakerMax concurrent requests per cluster
Connection exhaustionPer-IP limitsMax 256 connections per source IP
Slow headers (Slowloris)Read timeout60-second header read deadline
Large headersSize limit64KB max header size
Request smugglingStrict parsingReject CL+TE, duplicate CL, whitespace CL
Path traversalNormalizationCollapse //, resolve .. before routing