Designing Highly Available Load Balancing Architectures
A load balancer can protect an application from individual backend failures, but only if the load-balancing layer itself is highly available. Replacing one application server with one load balancer simply moves the single point of failure.
Highly available load balancing requires redundancy across load balancers, backend instances, availability zones, and sometimes regions. It also requires reliable health detection, connection draining, capacity headroom, and a traffic-routing mechanism capable of bypassing failed infrastructure.
Table of Contents
- The Load Balancer as a Failure Domain
- Redundant Load Balancer Architectures
- Multi-Zone Load Balancing
- Health Checks and Failure Detection
- Capacity and Failure Planning
- Production Design Example
- Common Mistakes
- Production Checklist
- Conclusion
- Key Takeaway
- More Articles to Read
The Load Balancer as a Failure Domain
A basic horizontally scaled application might run several backend instances behind a single load balancer:
Internet
|
v
+---------------+
| Load Balancer |
+---------------+
/ | \
v v v
App 1 App 2 App 3
The application tier can tolerate an individual backend failure. The traffic entry point cannot.
If the load balancer fails, every healthy application instance becomes unreachable:
Internet
|
v
+---------------+
| Load Balancer | X
+---------------+
/ | \
App 1 App 2 App 3
healthy healthy healthy
Service unavailable
This illustrates an important availability principle: redundancy must exist at every critical layer of the request path.
A highly available system therefore needs to consider the complete chain:
- DNS and global routing;
- load-balancing infrastructure;
- network paths;
- availability zones;
- backend application instances;
- databases and other critical dependencies.
Redundancy in only the application tier does not make the complete service highly available.
The basic responsibilities of load balancers and backend selection are covered in Load Balancing Explained: Distributing Traffic at Scale.
Redundant Load Balancer Architectures
Load-balancing infrastructure generally uses one of two high-level redundancy models: active-passive or active-active. Both remove the dependency on a single load-balancer instance, but their traffic and failure behavior differ.
Active-Passive
In an active-passive architecture, one load balancer receives production traffic while another remains available as a standby.
Clients
|
v
Virtual IP
|
+-----------+-----------+
| |
v v
+------------+ +------------+
| LB Active | | LB Standby |
+------------+ +------------+
|
+----+----+
| |
v v
App 1 App 2
The standby continuously or periodically verifies that the active load balancer is alive. When failure is detected, ownership of the traffic endpoint moves to the standby.
On private infrastructure, this may involve a shared virtual IP and a protocol such as VRRP. In other environments, failover might happen through routing changes, service discovery, DNS, or provider-managed networking.
Advantages:
- simple traffic ownership;
- predictable failure behavior;
- lower synchronization requirements for some configurations;
- straightforward architecture for smaller environments.
Disadvantages:
- standby capacity normally handles little or no production traffic;
- failover is not instantaneous;
- active connections may be lost unless connection state is replicated;
- failure detection must avoid both slow failover and false failover.
The standby must also be tested regularly. Infrastructure that never handles traffic can silently become incapable of taking over because of configuration drift, expired certificates, software differences, or broken network permissions.
Active-Active
In an active-active architecture, multiple load-balancing nodes receive traffic simultaneously.
Clients
|
v
Traffic Routing
/ \
v v
+---------+ +---------+
| LB 1 | | LB 2 |
+---------+ +---------+
/ \ / \
v v v v
App 1 App 2 App 3 App 4
Traffic can be distributed through DNS, anycast, network routing, another load-balancing tier, or cloud-provider networking.
Advantages:
- all load-balancing capacity can serve production traffic;
- failure can often be handled by removing one node from routing;
- capacity scales horizontally;
- production traffic continuously exercises all active nodes.
Disadvantages:
- routing and health management are more complex;
- stateful behavior can require synchronization;
- failure can shift significant traffic to surviving nodes;
- configuration must remain consistent across the fleet.
| Characteristic | Active-Passive | Active-Active |
|---|---|---|
| Normal traffic | Primarily one active node | Multiple nodes |
| Standby capacity | Mostly unused | Used for production traffic |
| Failover | Promote standby | Remove failed node from routing |
| Scaling | Usually limited | Horizontal |
| Operational complexity | Lower | Higher |
| Capacity after failure | Standby becomes active | Traffic shifts to remaining active nodes |
Managed cloud load balancers commonly hide much of this infrastructure behind a regional service endpoint. The provider manages redundant load-balancing nodes, but application architects still need to design backend distribution, health checks, failure domains, and sufficient capacity.
Multi-Zone Load Balancing
Multiple load balancers inside one failure domain are not sufficient when the system must survive an availability-zone failure.
A stronger architecture distributes both the balancing layer and application capacity across zones:
Internet
|
v
Regional Endpoint
|
+-------------+-------------+
| |
Availability Zone A Availability Zone B
| |
v v
+---------+ +---------+
| LB Node | | LB Node |
+---------+ +---------+
/ \ / \
v v v v
App 1 App 2 App 3 App 4
If Zone A becomes unavailable, traffic must continue through Zone B.
This requires more than placing instances in different zones. The surviving zone must have enough capacity to absorb redistributed traffic.
Suppose normal traffic is 8,000 requests per second:
Zone A capacity: 5,000 req/s
Zone B capacity: 5,000 req/s
Normal:
Zone A --> 4,000 req/s
Zone B --> 4,000 req/s
Zone A fails:
Zone B --> 8,000 req/s required
Zone B --> 5,000 req/s available
Result: overload
The architecture is technically redundant but not failure-capable at the expected load.
One solution is enough pre-provisioned capacity for each failure domain to absorb the required failover traffic. Another is autoscaling, but autoscaling has reaction time: new instances must be requested, started, initialized, registered, and made ready.
Critical systems therefore commonly maintain capacity headroom instead of assuming scaling will happen quickly enough during an outage.
Cross-zone balancing also affects traffic distribution. Without it, a load-balancer node may route only to targets in its own zone. With cross-zone balancing, traffic can be distributed across healthy targets in multiple zones.
The correct approach depends on availability requirements, network costs, locality requirements, and whether each zone is expected to operate independently.
Health Checks and Failure Detection
High availability depends on detecting failures quickly enough to stop routing traffic to unhealthy infrastructure without reacting so aggressively that transient problems cause unnecessary failovers.
Failure detection generally happens at multiple levels:
- load-balancer node health;
- availability-zone reachability;
- backend target health;
- application readiness;
- sometimes global endpoint or regional health.
A backend might be configured with:
health_check:
path: /ready
interval_seconds: 10
timeout_seconds: 3
# Avoid removing a backend after one transient failure.
unhealthy_threshold: 3
# Require repeated success before restoring traffic.
healthy_threshold: 2
With a 10-second interval and an unhealthy threshold of three, detection may take roughly tens of seconds depending on timing and implementation. Lowering the interval or threshold improves detection speed but increases sensitivity to transient failures.
This creates a fundamental trade-off:
| Configuration | Benefit | Risk |
|---|---|---|
| Short interval | Faster detection | More health-check traffic and sensitivity |
| Low failure threshold | Fast removal | Transient errors can remove healthy capacity |
| High failure threshold | Better tolerance of transient errors | Failed targets receive traffic longer |
| Complex dependency checks | Can detect inability to serve complete requests | Shared dependency failure can remove the entire fleet |
Health checks should answer whether the target should receive traffic. They should not become comprehensive infrastructure diagnostics.
Readiness, liveness, and dependency behavior require different failure semantics. More about these distinctions can be found in Health Checks, Readiness, and Liveness Probes.
Failure detection must also include recovery behavior. Immediately restoring full traffic after one successful check can overload a recovering instance. Some systems use slow start, warm-up periods, or gradually increasing weights to return capacity safely.
Capacity and Failure Planning
High availability is not just the ability to redirect traffic. The surviving infrastructure must be capable of processing that traffic.
Consider four backend instances:
Instance capacity: 2,000 req/s
Instances: 4
Total theoretical capacity: 8,000 req/s
Normal traffic: 6,000 req/s
At first glance, utilization is 75%. But if one instance fails:
Remaining capacity: 6,000 req/s
Traffic: 6,000 req/s
Utilization: 100%
Any additional traffic, latency increase, retry amplification, or downstream slowdown can now overload the remaining fleet.
A production design should therefore define its expected failure model:
- one backend instance lost;
- one load-balancer node lost;
- one availability zone lost;
- network partition between zones;
- dependency degradation;
- deployment temporarily reducing healthy capacity.
Capacity should then be evaluated under each required scenario rather than only under normal conditions.
Retries make this especially important. If clients retry failed requests while infrastructure capacity is already reduced, the system can experience retry amplification.
Normal traffic
10,000 req/s
|
v
Partial failure
20% requests fail
|
v
Clients retry
|
v
Additional request load
|
v
More saturation
|
v
More failures and retries
Timeouts, retry limits, exponential backoff, and jitter are therefore part of availability architecture even though they operate outside the load balancer itself. For a deeper explanation, see Timeouts, Retries, and Exponential Backoff.
Autoscaling can restore capacity, but it should not be treated as instantaneous failover. The important metric is time to usable capacity, not simply time to request another instance.
Production Design Example
Consider an API that must survive the loss of one availability zone without changing its public endpoint.
A production architecture can use a provider-managed regional load balancer with application instances distributed across three availability zones:
Clients
|
v
DNS
|
v
+------------------------+
| Regional Load Balancer |
| TLS + HTTP Routing |
+------------------------+
/ | \
/ | \
v v v
Zone A Zone B Zone C
| | |
+---+---+ +---+---+ +---+---+
| | | | | |
App App App App App App
1 2 3 4 5 6
The regional load balancer exposes a stable endpoint while its underlying infrastructure remains redundant. Each application instance registers only after passing readiness checks.
Assume each application instance safely handles 1,500 requests per second. Six instances provide 9,000 requests per second of application capacity.
If production traffic reaches 5,500 requests per second and an entire zone containing two instances fails, four instances remain:
Healthy instances after zone failure: 4
Safe capacity per instance: 1,500 req/s
Remaining capacity:
4 x 1,500 = 6,000 req/s
Production traffic:
5,500 req/s
Headroom:
500 req/s
The service remains operational, although capacity is now tight. Autoscaling should begin restoring redundancy before another failure or traffic increase occurs.
The target lifecycle should look like this during deployments and scaling:
- Start the application instance.
- Load configuration and establish required dependencies.
- Warm critical application state where appropriate.
- Pass readiness checks.
- Register with the load balancer.
- Receive production traffic.
- When removing the instance, stop new traffic first.
- Drain in-flight requests and long-lived connections.
- Terminate only after the drain period completes.
This prevents scaling events and deployments from creating artificial failures.
The load balancer should expose operational metrics such as:
- healthy and unhealthy target count by zone;
- requests per target and zone;
- active connections;
- backend response latency;
- load-balancer-generated errors;
- backend-generated errors;
- connection failures and resets;
- rejected or dropped traffic.
Metrics should be segmented by failure domain. A global 99.9% success rate can hide one availability zone experiencing severe errors while the remaining zones compensate.
If the availability requirement extends beyond a regional failure, another routing layer is required to direct traffic between independent regions. That architecture is covered in Global Load Balancing and Multi-Region Traffic Routing.
Common Mistakes
| Mistake | Why It Causes Problems | Better Approach |
|---|---|---|
| Using one load-balancer instance | The balancing layer becomes the single point of failure for every backend. | Use redundant managed infrastructure or multiple load-balancer nodes. |
| Placing all load balancers in one zone | A zone failure can remove the entire traffic entry layer. | Distribute load-balancing capacity across independent failure domains. |
| Spreading instances across zones without failover capacity | Remaining zones become overloaded when one zone disappears. | Capacity-plan against the required zone-loss scenario. |
| Relying entirely on autoscaling for failover | New capacity takes time to launch, initialize, and become ready. | Maintain enough headroom to survive failures during scaling delay. |
| Using overly aggressive health checks | Transient latency or dependency issues can remove healthy capacity and amplify an incident. | Tune intervals and thresholds using realistic failure behavior. |
| Using overly slow health checks | Failed targets continue receiving production requests for too long. | Set detection time according to service availability objectives and failure characteristics. |
| Checking every dependency in readiness | A shared downstream outage can make every backend disappear simultaneously. | Fail readiness only when the instance truly should not receive useful traffic. |
| Skipping connection draining | Deployments and scaling events terminate active requests and connections. | Deregister first, drain traffic, then terminate. |
| Ignoring retries during capacity planning | Failures generate additional requests precisely when available capacity is reduced. | Model retry amplification and enforce bounded retry policies. |
| Monitoring only global load-balancer metrics | Failures isolated to one target or zone can remain hidden behind healthy aggregate numbers. | Segment traffic, latency, health, and errors by backend and failure domain. |
Production Checklist
- Eliminate single load-balancer instances: provide redundancy at the traffic entry layer.
- Distribute across failure domains: place load-balancing and application capacity across multiple availability zones.
- Define the required failure model: explicitly decide whether the service must survive instance, node, zone, or regional failures.
- Capacity-plan for failures: calculate usable capacity after losing the largest required failure domain.
- Maintain headroom: avoid depending on instantaneous autoscaling during outages.
- Measure time to usable capacity: include startup, initialization, warming, health checks, and registration.
- Tune health checks: balance fast failure detection against false removal of healthy targets.
- Separate readiness from diagnostics: avoid making traffic eligibility depend on every optional downstream system.
- Enable connection draining: complete in-flight work before removing instances.
- Control retries: use bounded attempts, timeouts, backoff, and jitter to prevent retry storms.
- Test failover under load: remove instances and zones while realistic production-level traffic is running.
- Monitor per-zone capacity: detect imbalance before it becomes a failover problem.
- Alert on healthy target count: treat unexpected capacity reduction as an availability signal.
- Exercise standby infrastructure: regularly verify that passive components can actually accept production traffic.
- Document traffic dependencies: map DNS, load balancers, zones, applications, and critical downstream services.
Conclusion
Highly available load balancing requires redundancy beyond the backend application fleet. The traffic entry layer, availability zones, health detection, capacity model, and instance lifecycle must all continue functioning when infrastructure fails.
Active-passive and active-active designs provide load-balancer redundancy, while multi-zone architectures extend protection to larger failure domains. The architecture becomes truly resilient only when surviving components also have enough capacity to absorb redirected traffic.
Key Takeaway
High availability is not created by adding a load balancer; it is created by removing single points of failure from the complete traffic path. Design load-balancing infrastructure around explicit failure domains, maintain enough capacity to survive those failures, detect unhealthy components quickly but safely, and continuously verify failover behavior under realistic load.
More Articles to Read
- Load Balancing Explained: Distributing Traffic at Scale
- Round Robin vs Least Connections vs Consistent Hashing
- Sticky Sessions and Stateless Applications
- Traffic Routing Strategies for Zero-Downtime Deployments
- Global Load Balancing and Multi-Region Traffic Routing
- Load Balancing Best Practices for Production Systems
Comments (0)