When implementing multiple load balancers, DNS becomes your primary distribution mechanism. Modern DNS services support multiple A records (for IPv4) or AAAA records (for IPv6) for a single hostname, enabling round-robin distribution at the DNS level.
example.com. 300 IN A 192.0.2.1
example.com. 300 IN A 192.0.2.2
example.com. 300 IN A 192.0.2.3
There are two primary approaches to multi-LB architectures:
- Active-Passive: One LB handles traffic while others remain on standby
- Active-Active: All LBs share traffic load simultaneously
For geographically distributed setups, GSLB solutions like:
# Example AWS Route53 latency-based routing
resource "aws_route53_record" "www" {
zone_id = aws_route53_zone.primary.zone_id
name = "www.example.com"
type = "A"
latency_routing_policy {
region = "us-west-2"
set_identifier = "us-west-2"
alias {
name = aws_lb.west.dns_name
zone_id = aws_lb.west.zone_id
evaluate_target_health = true
}
}
latency_routing_policy {
region = "eu-west-1"
set_identifier = "eu-west-1"
alias {
name = aws_lb.east.dns_name
zone_id = aws_lb.east.zone_id
evaluate_target_health = true
}
}
}
Implement comprehensive health checks to ensure traffic only routes to healthy LBs:
# NGINX Plus active health checks
upstream backend {
zone backend 64k;
server 10.0.0.1:80;
server 10.0.0.2:80;
health_check interval=5s fails=3 passes=2 uri=/health;
health_check_timeout 3s;
}
When using multiple active LBs, implement distributed session storage:
# Redis session storage configuration for Node.js
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({
host: 'redis-cluster.example.com',
port: 6379,
ttl: 86400
}),
secret: 'your_secret_key',
resave: false,
saveUninitialized: false
}));
For configuration management across multiple LBs:
# Ansible playbook for consistent LB configuration
- hosts: loadbalancers
become: true
tasks:
- name: Ensure haproxy is installed
apt:
name: haproxy
state: present
- name: Deploy haproxy config
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart haproxy
handlers:
- name: restart haproxy
service:
name: haproxy
state: restarted
Implement centralized monitoring for all LBs:
# Prometheus configuration for multiple LB instances
scrape_configs:
- job_name: 'haproxy'
static_configs:
- targets: ['lb1.example.com:9101', 'lb2.example.com:9101', 'lb3.example.com:9101']
- job_name: 'nginx'
static_configs:
- targets: ['lb4.example.com:9113', 'lb5.example.com:9113']
When architecting high-availability systems, many developers encounter the paradox: if DNS typically resolves to a single IP, how can we distribute traffic across multiple load balancers? The misconception stems from thinking about DNS as a static 1:1 mapping rather than a dynamic routing mechanism.
The simplest approach is DNS round-robin with multiple A records:
example.com. IN A 192.0.2.1 example.com. IN A 192.0.2.2 example.com. IN A 192.0.2.3
However, this has limitations due to DNS caching. For better control, consider weighted DNS responses using Route 53:
const params = { HostedZoneId: 'Z1PA6795UKMFR9', ChangeBatch: { Changes: [ { Action: "CREATE", ResourceRecordSet: { Name: "api.example.com", Type: "A", SetIdentifier: "lb-east-1", Weight: 30, AliasTarget: { HostedZoneId: "Z35SXDOTRQ7X7K", DNSName: "dualstack.lb-east-1.elb.amazonaws.com", EvaluateTargetHealth: true } } } ] } };
For global distribution, anycast routing allows multiple load balancers to share the same IP address. Cloud providers implement this differently:
# AWS Global Accelerator configuration resource "aws_globalaccelerator_accelerator" "example" { name = "multi-lb-accelerator" ip_address_type = "IPV4" enabled = true } resource "aws_globalaccelerator_listener" "example" { accelerator_arn = aws_globalaccelerator_accelerator.example.id client_affinity = "SOURCE_IP" protocol = "TCP" port_range { from_port = 80 to_port = 80 } }
Implementing proper health checks ensures traffic only reaches healthy endpoints. Here's a HAProxy configuration for active-passive setups:
frontend http-in bind *:80 default_backend servers backend servers balance roundrobin option httpchk GET /health server lb1 192.168.1.10:80 check backup server lb2 192.168.1.11:80 check
Common architectural approaches include:
- Tiered load balancing (global LB → regional LB → service LB)
- Active-active configurations with BGP peering
- Cloud-specific solutions like AWS ALB + NLB combinations
For Kubernetes environments, consider this Ingress configuration:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: multi-lb-ingress annotations: nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri" spec: ingressClassName: nginx rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: web-service port: number: 80