AlgoInsight

Free lesson · System Design Fundamentals

Availability

Easy8 min readsystem-designhlddistributed-systems

Lesson 2.2 - Availability

The second lesson of Module 2.

Availability is the simplest question in system design - "is the system working right now?" - with the most consequential answer. When your e-commerce checkout is unavailable for an hour on Black Friday, the lost revenue is real and permanent. When your banking API is unavailable for 10 minutes, customers panic and call support. When your SaaS dashboard is unavailable for a day, customers evaluate competitors. Availability is measured as a percentage of uptime, and the difference between 99.9% and 99.99% - which looks like a tiny 0.09% improvement - is the difference between 8.7 hours and 52 minutes of annual downtime. Each additional decimal point (each "nine") is exponentially harder and more expensive to achieve.

Interactive animation: Step through how each extra nine shrinks the downtime budget.

The Nines

Interactive animation: From 99% to 99.999%: what each nine allows per year.

Availability is expressed as a percentage of time the system is operational and serving requests correctly. The industry convention is "nines" - how many 9s are in the percentage:

Availability Downtime per year Downtime per month Name Typical systems
99% 3.65 days 7.3 hours Two nines Internal tools, batch jobs
99.9% 8.76 hours 43.8 minutes Three nines Standard web applications
99.95% 4.38 hours 21.9 minutes Three and a half nines Important business applications
99.99% 52.6 minutes 4.38 minutes Four nines Critical infrastructure, payments
99.999% 5.26 minutes 26.3 seconds Five nines Core cloud services (S3, Route 53)
flowchart LR
    N2["99%\nTwo nines\n3.65 days/year\nInternal tools"]
    N3["99.9%\nThree nines\n8.76 hours/year\nMost web apps"]
    N4["99.99%\nFour nines\n52 minutes/year\nPayment systems"]
    N5["99.999%\nFive nines\n5 minutes/year\nS3, DNS"]
    
    N2 -->|"10x harder"| N3
    N3 -->|"10x harder"| N4
    N4 -->|"10x harder"| N5

    style N2 fill:#fb7185,stroke:#f43f5e,color:#000
    style N3 fill:#fbbf24,stroke:#f59e0b,color:#000
    style N4 fill:#34d399,stroke:#10b981,color:#000
    style N5 fill:#a78bfa,stroke:#8b5cf6,color:#000
A progression diagram showing the nines of availability from two nines to five nines. Two nines - 99 percent - allows 3.65 days of downtime per year, acceptable for internal tools. Three nines - 99.9 percent - allows 8.76 hours per year, the standard for most production web applications. Four nines - 99.99 percent - allows just 52 minutes per year, required for critical infrastructure like payment processing, databases, and authentication services. Five nines - 99.999 percent - allows only 5.26 minutes per year, achieved only by core infrastructure services like Amazon S3 or Route 53. Each step from one level to the next is approximately ten times harder to achieve. Going from three nines to four nines is not a small incremental improvement - it requires fundamentally different engineering: automated failover, redundant everything, multi-availability-zone deployment, chaos engineering, and rigorous on-call operations. Most startups should target three nines. Most mature production services target three-and-a-half to four nines. Five nines is the domain of infrastructure that other infrastructure depends on.

The key insight: each nine is exponentially harder to achieve. Going from 99% to 99.9% might require adding a load balancer and a second server (M4). Going from 99.9% to 99.99% requires automated failover, health checks (M4.1), redundant databases (M28), multi-AZ deployment, and a 24/7 on-call team with runbooks. Going from 99.99% to 99.999% requires multi-region architecture, chaos engineering (intentionally injecting failures to test resilience), and the kind of engineering investment that only the largest companies can justify. Each nine costs roughly 10x what the previous one cost - in engineering time, infrastructure spend, and operational discipline.

How Availability Is Calculated

Uptime-based (simple):

Availability = Uptime / (Uptime + Downtime) × 100

If a service was up for 719 hours and down for 1 hour in a 30-day month: 719/720 = 99.86% - just below three nines.

Request-based (more practical):

Availability = Successful requests / Total requests × 100

A service that handled 999,000 successful responses and 1,000 errors out of 1,000,000 total requests: 999,000/1,000,000 = 99.9% - exactly three nines. The server never went "down" - it was always responding - but 0.1% of responses were errors. This request-based definition is more useful for modern services because it captures partial failures (the server is up but returning errors for some requests, perhaps because one database shard is unavailable).

Availability of Components: Series vs Parallel

Interactive animation: In a chain, every component has to be up. Availability multiplies down.

Components in series (ALL must work for the system to work):

Overall availability = A₁ × A₂ × A₃ × ...

An API server (99.9%) calling a database (99.9%) calling a cache (99.9%): 0.999 × 0.999 × 0.999 = 99.7%. Each component in the chain reduces the total. A system with 10 components in series, each at 99.9%, has an overall availability of 99.9%¹⁰ = 99.0% - only two nines! Every dependency you add to the critical path reduces your availability. This is why minimizing the dependency chain matters for reliability.

Components in parallel (ANY can serve the request):

Overall availability = 1 - (1 - A₁) × (1 - A₂) × ...

Two API servers behind a load balancer, each 99.9%: 1 - (0.001 × 0.001) = 99.9999% - nearly six nines! Adding a third: 1 - (0.001³) = 99.9999999% - nine nines. Redundancy is the primary tool for improving availability. A single server at 99.9% gives 8.7 hours of downtime per year. Two servers in parallel give 32 seconds. The math is powerful.

flowchart TD
    subgraph Series["Series (ALL must work)"]
        S1["API Server\n99.9%"] --> S2["Database\n99.9%"] --> S3["Cache\n99.9%"]
        Result1["Overall: 99.7%\n(WORSE than any single component)"]
    end
    
    subgraph Parallel["Parallel (ANY can work)"]
        LB["Load Balancer"]
        P1["Server 1\n99.9%"]
        P2["Server 2\n99.9%"]
        LB --> P1
        LB --> P2
        Result2["Overall: 99.9999%\n(BETTER than any single component)"]
    end

    style Result1 fill:#fb7185,stroke:#f43f5e,color:#000
    style Result2 fill:#34d399,stroke:#10b981,color:#000
Two diagrams showing how component arrangement affects availability. In the series arrangement, an API server, database, and cache are connected in sequence - a request must pass through all three. Each component has 99.9 percent individual availability. The overall system availability is the product: 99.9 percent times 99.9 percent times 99.9 percent equals 99.7 percent. The system is LESS available than any single component because any failure in the chain breaks the whole system. In the parallel arrangement, two servers sit behind a load balancer. Each server has 99.9 percent availability. The system fails only if BOTH servers fail simultaneously. The probability of both failing: 0.1 percent times 0.1 percent equals 0.0001 percent. The overall availability is 99.9999 percent - nearly six nines. The system is FAR MORE available than either individual component. This is the mathematical foundation of high availability: reduce series dependencies (minimize the chain) and add parallel redundancy (add replicas behind load balancers).

The practical implication: to improve availability, do two things: (1) minimize the number of components in series on the critical path (don't add dependencies you don't need), and (2) add parallel redundancy for every component that IS on the critical path (redundant servers, redundant databases, redundant load balancers). Both are necessary - redundancy at one layer doesn't compensate for an unnecessarily long dependency chain.

SLAs, SLOs, and Error Budgets (Preview)

Three related concepts that get full treatment in M43 (Observability) but deserve an introduction here:

SLA (Service Level Agreement): a contractual promise to customers about availability. "We guarantee 99.9% availability; if we miss it, you get a 10% service credit." SLAs have financial consequences - they're business commitments, not engineering targets. AWS S3's SLA promises 99.9% availability; dropping below triggers automatic service credits.

SLO (Service Level Objective): an internal engineering target that's stricter than the SLA. If the SLA promises 99.9%, the internal SLO might target 99.95%. The margin between SLO and SLA is the buffer - the team investigates when the SLO is breached, before the SLA is breached and the business owes money.

Error budget: the amount of allowed unreliability in a period. If your SLO is 99.9% availability per month, you can afford 43.8 minutes of downtime. That's your error budget - you can "spend" it on risky deployments, experiments, or migrations. When the budget is nearly spent, you slow down and focus on reliability. When there's budget remaining, you ship faster. This framework (from Google's SRE practice) turns availability from a vague goal into a quantified resource that engineering and product teams share.

A Brandon Story: The 99.95% That Cost $240,000

A team I'd advised offered a 99.95% SLA to their enterprise customers. This allowed 21.9 minutes of downtime per month. For the first 14 months, they achieved 99.97-99.99% - comfortably above the SLA. Then they had a database migration incident.

The migration was scheduled for a maintenance window (Saturday 2am), but a misconfigured rollback script caused the database to be unavailable for 3 hours and 47 minutes. Monthly availability: 99.48%. The SLA was breached. Under their contract terms, every enterprise customer received a 25% service credit for that month. With 60 enterprise customers at an average of $4,000/month: 60 × $4,000 × 25% = $60,000 in credits.

Worse: two enterprise customers used the SLA breach as grounds to renegotiate their contracts - arguing that the reliability wasn't worth the premium tier. One downgraded; one left entirely. Estimated revenue impact over the next year:

80,000 in lost contracts.

A single 3-hour-47-minute outage cost $240,000 in direct credits and lost revenue. The maintenance window saved the team 4 hours of developer time on a Sunday afternoon.

After the incident, three things changed:

  1. Blue-green database migrations (M40) - new database provisioned alongside old, traffic cut over atomically, old database kept as instant rollback. No downtime during migration.
  2. Error budget tracking on a monthly dashboard - the team could see "we have 18 minutes of budget remaining this month" and make risk decisions accordingly.
  3. SLA-aware deployment policy - if more than 50% of the month's error budget was spent, risky operations (migrations, major deploys) were deferred to the next month.

Lessons:

Six Takeaways from This Lesson

  1. Availability = uptime percentage. 99.9% = 8.7 hours/year. 99.99% = 52 minutes/year. Each nine is 10x harder.

  2. Series reduces availability (multiply). Parallel improves it (one minus product of failure rates). Minimize dependencies; maximize redundancy.

  3. Request-based availability (successful/total) is more practical than uptime-based for modern services - it captures partial failures.

  4. SLA is the contract (external). SLO is the target (internal). Error budget is the allowed unreliability. SLO should be stricter than SLA.

  5. Every dependency on the critical path reduces availability. 10 components at 99.9% each = 99.0% overall. Add only necessary dependencies.

  6. Availability has a dollar value. An SLA breach at 99.95% with enterprise customers can cost hundreds of thousands in credits and lost contracts.

Try It

Exercise: Warmup (15 minutes). Your system has an API server (99.9%) and a database (99.95%) in series. Calculate the overall availability. How many minutes of downtime per month does that allow? Now add a cache (99.99%) in series - how does it change?

Exercise: Core (25 minutes). You need 99.99% availability for your checkout service. Your single server achieves 99.9%. How many servers in parallel do you need to reach 99.99%? Show the math. What else besides redundant servers is needed (load balancer, health checks, auto-failover)?

Exercise: Stretch (45 minutes). Read your cloud provider's SLA for their managed database service (AWS RDS, GCP Cloud SQL, or Azure SQL). What's the availability promise? What are the service credit tiers? What's explicitly excluded from the SLA (scheduled maintenance, customer-caused issues)?

What's Next

Lesson 2.3 covers reliability - which sounds like availability but isn't. A system can be available (responding to every request) and unreliable (responding incorrectly).

Back to System Design Fundamentals