Why Load Balance?#

A single server has finite capacity. Load balancing distributes traffic across multiple servers to achieve:

  • High availability — if one server fails, others handle traffic
  • Scalability — add servers to handle more load
  • Performance — distribute work evenly
flowchart LR
    C1["Client"] --> LB["Load Balancer"]
    C2["Client"] --> LB
    C3["Client"] --> LB
    
    LB --> S1["Server 1"]
    LB --> S2["Server 2"]
    LB --> S3["Server 3"]

Load Balancing Algorithms#

AlgorithmHow It WorksBest For
Round RobinRotate sequentiallyEqual-capacity servers
Weighted Round RobinRotate with weights (2:1:1)Mixed-capacity servers
Least ConnectionsSend to server with fewest active connectionsVariable request duration
Least Response TimeSend to fastest-responding serverHeterogeneous backends
IP HashHash client IP → consistent serverSession affinity without cookies
RandomRandom selectionSimple, effective at scale

Choosing an Algorithm#

flowchart TD
    Q1{"All servers equal capacity?"}
    Q1 -->|Yes| Q2{"Requests take similar time?"}
    Q1 -->|No| WRR["Weighted Round Robin"]
    Q2 -->|Yes| RR["Round Robin"]
    Q2 -->|No| LC["Least Connections"]

Layer 4 vs Layer 7 Load Balancing#

AspectLayer 4 (Transport)Layer 7 (Application)
InspectsIP + PortHTTP headers, URL, cookies
SpeedFaster (less processing)Slower (deep inspection)
Routing decisionsBased on IP/port onlyBased on URL path, headers, content
TLS terminationPass-through or terminateAlways terminates
Use caseTCP/UDP services, databasesWeb applications, APIs

Layer 7 Routing Examples#

/api/*        → API server pool
/static/*     → CDN or static server pool
/admin/*      → Admin server (restricted)
Host: mobile.* → Mobile-optimized servers

AWS Load Balancer Types#

TypeLayerProtocolsUse Case
ALB (Application)7HTTP, HTTPS, gRPCWeb apps, APIs, microservices
NLB (Network)4TCP, UDP, TLSHigh performance, static IPs
CLB (Classic)4/7HTTP, TCPLegacy (avoid for new projects)

Health Checks#

Load balancers must know which backends are healthy:

sequenceDiagram
    participant LB as Load Balancer
    participant S1 as Server 1
    participant S2 as Server 2
    
    loop Every 30s
        LB->>S1: GET /health
        S1->>LB: 200 OK ✓
        LB->>S2: GET /health
        S2->>LB: 503 Error ✗
    end
    
    Note over LB: Remove Server 2 from pool

Health Check Configuration#

ParameterTypical ValuePurpose
Path/health or /healthzEndpoint to check
Interval30sHow often to check
Timeout5sMax wait for response
Healthy threshold3Consecutive successes to mark healthy
Unhealthy threshold2Consecutive failures to mark unhealthy

Health Check Best Practices#

  • Check actual dependencies (database, cache) — not just “process is running”
  • Return quickly — don’t do expensive operations
  • Separate liveness (is the process alive?) from readiness (can it serve traffic?)

Reverse Proxy#

A reverse proxy sits in front of servers and handles client requests on their behalf:

flowchart LR
    Client --> RP["Reverse Proxy<br/>(nginx, HAProxy)"]
    RP --> S1["Backend 1"]
    RP --> S2["Backend 2"]

Functions Beyond Load Balancing#

FunctionBenefit
TLS terminationBackends don’t handle encryption
CachingReduce backend load for static content
Compressiongzip/brotli responses
Rate limitingProtect backends from abuse
Request routingPath-based routing to different services
Header manipulationAdd/remove/modify headers
Connection poolingReuse backend connections

Session Persistence (Sticky Sessions)#

Some applications need the same client to reach the same server:

MethodHowTrade-off
Cookie-basedLB sets a cookie with server IDRequires cookie support
IP hashHash client IP to serverBreaks with NAT/proxies
Application-managedExternalize session (Redis)Best — no stickiness needed

Best practice: Externalize session state (Redis, DynamoDB) so any server can handle any request. Avoid sticky sessions when possible.


High Availability Patterns#

Active-Active#

All servers handle traffic simultaneously:

LB → Server 1 (active)
   → Server 2 (active)
   → Server 3 (active)

Active-Passive (Failover)#

Standby takes over when primary fails:

LB → Server 1 (active) ← handles all traffic
   → Server 2 (standby) ← takes over on failure

Multi-AZ#

Distribute across availability zones for datacenter-level resilience:

AZ-a: Server 1, Server 2
AZ-b: Server 3, Server 4
LB distributes across both AZs

Key Takeaways#

  1. Round Robin for simple cases, Least Connections for variable workloads
  2. Layer 7 (ALB) for HTTP routing, Layer 4 (NLB) for raw TCP/UDP performance
  3. Health checks are critical — unhealthy servers must be removed automatically
  4. Externalize session state — avoid sticky sessions
  5. Reverse proxies do more than load balance: TLS, caching, rate limiting
  6. Multi-AZ for high availability — survive datacenter failures