Availability

Backend Fundamentals · System Design · 7 min read

1. What problem does this solve?

  • Problem: A single server or component can fail (hardware crash, software bug, network outage). If the system is not designed to tolerate such failures, users experience downtime.
  • Why it matters: Modern web services expect continuous operation. Even a few minutes of outage can cost revenue, damage reputation, and violate SLAs.
  • Consequences of ignoring availability:
    • Users see error pages or timeouts.
    • Automated monitoring alerts trigger, causing firefighting.
    • Data loss or corruption if writes are lost during a crash.
  • Real‑world appearance:
    • E‑commerce: checkout must stay online during traffic spikes.
    • Social media: feeds must keep delivering even if a data center goes down.
    • Financial services: trading platforms require 99.999% uptime.

2. Mental model

Analogy: A city’s power grid

  • Single power plant → one point of failure.
  • Multiple plants + automatic switching → if one plant fails, the grid keeps running.
  • Load balancer is like the grid’s switchboard, routing power (requests) to healthy plants (servers).
  • Health checks are the sensors that detect a plant’s status.

Engineering model

  • Redundancy: duplicate components (servers, databases).
  • Failover: automatic switch to a healthy replica when one fails.
  • Health checks: periodic probes that inform the load balancer which instances are alive.
  • Graceful degradation: if a non‑critical component fails, the system still serves core functionality.

3. Deep explanation

TopicExplanation
Internals• Load balancer (NGINX, HAProxy, AWS ELB) distributes traffic.
• Health‑check endpoints (/health) return 200 OK when healthy.
• Replicated databases (PostgreSQL streaming replication, MongoDB replica set, Redis Sentinel).
• Leader election (Raft, Paxos) for write‑consistency.
Important terminology• High Availability (HA) – system uptime ≥ 99.99%.
• Redundancy – duplicate components.
• Failover – automatic switch to a backup.
• Quorum – majority of nodes required for a decision.
• Circuit Breaker – stops traffic to a failing service.
Trade‑offs• CAP theorem: Consistency + Availability + Partition tolerance – you can only have two.
• Latency vs. Replication: More replicas → higher write latency.
• Cost vs. Uptime: Extra nodes, cross‑region replication increase spend.
Failure modes• Single point of failure (SPOF): e.g., one load balancer.
• Network partition: nodes cannot communicate.
• Data loss: writes lost before replication.
• Health‑check flapping: false positives/negatives.
Limitations• 100 % uptime is impossible; you can only approach it.
• Adding redundancy introduces complexity and potential new failure modes.
Where it fits• At the edge: load balancers, API gateways.
• In the middle: microservice clusters, message brokers.
• At the data layer: database replicas, sharding.
Interactions• Reliability: Availability is a subset of reliability.
• Observability: health checks, metrics, logs are essential.
• Performance: load balancing can improve throughput.
• Security: ensure health‑check endpoints are protected.

4. How it works

  1. Client sends request → to DNS → resolves to load balancer IP.
  2. Load balancer receives request, checks its routing table.
  3. Health check: LB periodically queries /health on each backend.
  4. Routing: LB forwards request to a healthy instance.
  5. Backend processes request, may read/write to replicated DB.
  6. Response travels back through LB to client.
  7. If a backend fails: LB stops routing to it until health check passes again.
sequenceDiagram
    participant Client
    participant LB as Load Balancer
    participant Service1
    participant Service2
    participant DB1
    participant DB2

    Client->>LB: GET /api/data
    LB->>Service1: Forward request
    Service1->>DB1: SELECT * FROM users
    DB1-->>Service1: Result
    Service1-->>LB: 200 OK
    LB-->>Client: 200 OK

    Note over LB: Health check fails on Service1
    LB->>Service2: Forward request

5. Practical implementation

5.1 Node.js + Express + NGINX load balancer

app.ts

import express from 'express';
const app = express();
const PORT = process.env.PORT || 3000;

// Simple health endpoint
app.get('/health', (_req, res) => {
  // In production, check DB, cache, etc.
  res.status(200).send('OK');
});

// Core API
app.get('/api/users', async (req, res) => {
  // Simulate DB read
  const users = await getUsersFromDB();
  res.json(users);
});

app.listen(PORT, () => {
  console.log(`Server listening on ${PORT}`);
});

nginx.conf

events {}
http {
  upstream backend {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
  }

  server {
    listen 80;

    location / {
      proxy_pass http://backend;
    }

    # Health check endpoint
    location /health {
      proxy_pass http://backend;
    }
  }
}
  • Run two Node instances on ports 3000 & 3001.
  • NGINX will stop sending traffic to an instance that fails 3 times in 30 s.
  • Health checks are performed automatically by NGINX.

5.2 Redis Sentinel for HA

import { createClient } from 'redis';

const sentinel = createClient({
  sentinels: [
    { host: 'redis-1.example.com', port: 26379 },
    { host: 'redis-2.example.com', port: 26379 }
  ],
  name: 'mymaster'
});

sentinel.on('error', err => console.error('Redis error:', err));

async function get(key: string) {
  return await sentinel.get(key);
}
  • Sentinel monitors the master and promotes a replica if the master fails.
  • The client automatically reconnects to the new master.

6. Production considerations

ConcernWhat to do
ScalabilityUse auto‑scaling groups; keep health checks lightweight.
ReliabilityDeploy across multiple AZs/regions; use multi‑master or quorum.
SecuritySecure health endpoints (TLS, auth); restrict LB IPs.
ObservabilityEmit metrics (up, request_latency_seconds), logs, and traces.
PerformanceCache health check responses; avoid heavy DB checks in /health.
Error handlingReturn 503 when unhealthy; implement retries with backoff.
Resource usageAvoid over‑provisioning; use container orchestration to manage replicas.
Operational concernsAutomate failover testing; monitor replication lag.
Failure recoveryUse automated scripts to restart failed services; keep backups.
DeploymentBlue/green or canary releases to test new instances before routing traffic.

7. Common mistakes

MistakeWhy it hurts
No health checksLoad balancer will keep sending traffic to dead nodes.
Single load balancerBecomes SPOF; add a second LB behind a DNS round‑robin or use a cloud ELB.
Health check hits DBCan cause false negatives during heavy load; use lightweight checks.
Ignoring replication lagReads may see stale data; use read replicas with awareness.
Over‑retryingCreates thundering herd; use exponential backoff.
Hard‑coding IPsBreaks when scaling; use service discovery.
Not testing failoverYou’ll discover issues only in production.

8. Senior engineer perspective

  • Architecture decisions:
    • Multi‑region vs. single‑region HA.
    • Consistency model: eventual vs. strong.
    • Use of distributed consensus (Raft) for leader election.
  • Trade‑offs:
    • Higher availability → higher cost (more nodes, cross‑region traffic).
    • Strong consistency → lower availability under partitions.
  • Bottlenecks:
    • Load balancer capacity.
    • Database write throughput.
    • Network latency between regions.
  • Failure scenarios:
    • Network partition: use quorum to decide.
    • Data center outage: rely on cross‑region replication.
  • Monitoring:
    • Uptime dashboards, replication lag alerts, health‑check metrics.
  • Cost/performance:
    • Evaluate cost of extra replicas vs. SLA penalties.
  • When NOT to use:
    • For low‑traffic internal tools where 99.9% uptime is acceptable.
    • When consistency is more critical than availability (e.g., banking).

9. Interview questions

1BeginnerWhat is a health check and why is it important?
Answer
: A health check is an endpoint that reports whether a service is functioning. It allows load balancers to stop routing traffic to unhealthy instances, preventing user-facing errors.
2BeginnerExplain the difference between a load balancer and a reverse proxy.
Answer
: A load balancer distributes traffic across multiple backends, often with health checks. A reverse proxy forwards requests to a single backend and may cache responses. Many reverse proxies also provide load balancing features.
3SeniorHow does the CAP theorem influence your design of a highly available database cluster?
Answer
: In a network partition, you must choose between consistency and availability. If you prioritize availability, you may allow writes to proceed on a majority of nodes (quorum) and resolve conflicts later. If you prioritize consistency, you may block writes until all nodes agree.
4SeniorDescribe a scenario where a circuit breaker improves system availability.
Answer
: If a downstream microservice is overloaded, a circuit breaker trips after a threshold of failures, immediately returning a fallback response. This prevents cascading failures and gives the downstream service time to recover.
5Scenario/DebuggingA user reports intermittent 503 errors from your API. Your logs show that the load balancer is routing traffic to a backend that occasionally returns 500. What steps would you take to diagnose and fix the issue?
Answer
:
  • Check backend health‑check logs to see if the instance is marked unhealthy.
  • Verify that the health‑check endpoint is lightweight and not hitting the DB.
  • Inspect the backend’s error logs for root causes (e.g., memory leak).
  • Ensure the load balancer’s max_fails and fail_timeout settings are appropriate.
  • If the issue is transient, consider adding a retry with backoff or a circuit breaker.

10. Hands‑on task

Goal: Build a simple two‑instance Node.js service behind NGINX with health checks, then simulate a failure.

  1. Clone the repo and run npm install.
  2. Start two Node instances: node app.ts --port=3000 and node app.ts --port=3001.
  3. Start NGINX with the provided nginx.conf.
  4. Verify that /api/users works from a browser or curl.
  5. Stop one Node instance and observe that NGINX stops routing to it after 3 failures.
  6. Add a /health endpoint that randomly fails 30 % of the time and observe how NGINX reacts.
  7. Document the observed behavior and explain why NGINX stops sending traffic.

11. Quick revision

  • Availability = uptime; goal is 99.99%+ for critical services.
  • Redundancy + failover = core of HA.
  • Load balancer routes traffic; health checks inform routing.
  • Replicated databases (PostgreSQL streaming, MongoDB replica set, Redis Sentinel).
  • CAP theorem: Availability vs. Consistency under partitions.
  • Circuit breakers prevent cascading failures.
  • Monitoring: uptime, health‑check metrics, replication lag.
  • Common pitfalls: no health checks, single LB, heavy health checks.
  • Senior decisions: multi‑region, quorum size, cost vs. SLA.

12. References