---
title: "05 — Availability Patterns: Fail-Over and Replication"
uid: availability-patterns
tags: ["availability", "replication", "redundancy", "roadmap:system-design", "failover", "system-design"]
excerpt: "Availability is bought with redundancy — fail-over (a standby takes over) and replication (copies stay in sync so any one can serve). Both add cost and leave residual risks."
date: 2026-08-13T03:27:34+0000
source: https://www.aveshina.my.id/en/blog/availability-patterns
---

"Just add more servers" was my availability strategy, and it skipped the structural choices underneath. Writing it down gave me a model I can actually apply: **availability is bought with redundancy, and the two structural patterns for spending that redundancy are fail-over (a standby takes over when the active dies) and replication (copies stay in sync so any one can serve).** [1][2] Both add cost and complexity, and both leave specific residual risks worth knowing.

The framing that landed is that "high availability" is not a feature a product has; it is a budget you spend. Every "9" of uptime costs real money in duplicate hardware, and the question is always _where_ you place the redundancy and _what failure mode_ it covers. Fail-over covers a whole component dying; replication covers both death _and_ load-spreading, at the cost of keeping the copies consistent [1].

## Fail-over: the standby takes over

Fail-over is the pattern where a primary component handles work, a secondary stands by, and the secondary is promoted if the primary fails [1][2]. The two flavors differ in whether the standby does useful work before the failure:

- **Active-passive** (a.k.a. master-slave). Heartbeats flow between the active and the passive. Only the active serves traffic. If the heartbeat stops, the passive grabs the active's IP and resumes service. The downtime depends on whether the passive was already running ("hot" standby, fast) or has to boot from cold ("cold" standby, slow) [1].
- **Active-active** (a.k.a. master-master). Both servers serve traffic and spread the load. DNS (for public-facing) or application logic (for internal) must know about both. If one dies, the other just keeps going with the full load [1].

```figure
<svg viewBox="0 0 740 240" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Two fail-over flavors. Left, Active-Passive: one green Active server serves traffic while a dim Standby waits; a heartbeat line connects them; if Active fails the Standby takes the IP. Right, Active-Active: two green servers both serve traffic and share the load.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- Active-Passive -->
    <text x="185" y="24" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">Active–Passive</text>
    <text x="185" y="40" font-size="10" fill="#64748b" text-anchor="middle">one serves, one waits</text>
    <!-- active -->
    <rect x="60" y="60" width="100" height="50" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="2"/>
    <text x="110" y="82" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">Active</text>
    <text x="110" y="99" font-size="9" fill="#052e16" text-anchor="middle">serves all traffic</text>
    <!-- passive -->
    <rect x="210" y="60" width="100" height="50" rx="8" fill="#f1f5f9" stroke="#94a3b8" stroke-width="1.5" stroke-dasharray="4 3"/>
    <text x="260" y="82" font-size="12" font-weight="700" fill="#475569" text-anchor="middle">Standby</text>
    <text x="260" y="99" font-size="9" fill="#475569" text-anchor="middle">idle until failover</text>
    <!-- heartbeat -->
    <line x1="160" y1="85" x2="210" y2="85" stroke="#ca8a04" stroke-width="1.5" stroke-dasharray="3 3"/>
    <text x="185" y="78" font-size="9" fill="#422006" text-anchor="middle">heartbeat</text>
    <!-- failover arrow -->
    <path d="M260,110 C260,140 160,140 110,120" fill="none" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="4 3" marker-end="url(#faarrow)"/>
    <text x="185" y="155" font-size="10" fill="#dc2626" text-anchor="middle" font-style="italic">on failure, standby takes the IP</text>

    <!-- Active-Active -->
    <text x="555" y="24" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">Active–Active</text>
    <text x="555" y="40" font-size="10" fill="#64748b" text-anchor="middle">both serve, shared load</text>
    <rect x="440" y="60" width="100" height="50" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="2"/>
    <text x="490" y="82" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">Active A</text>
    <text x="490" y="99" font-size="9" fill="#052e16" text-anchor="middle">half the load</text>
    <rect x="570" y="60" width="100" height="50" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="2"/>
    <text x="620" y="82" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">Active B</text>
    <text x="620" y="99" font-size="9" fill="#052e16" text-anchor="middle">half the load</text>
    <line x1="540" y1="85" x2="570" y2="85" stroke="#64748b" stroke-width="1.5"/>
    <text x="555" y="155" font-size="10" fill="#1e1b4b" text-anchor="middle" font-style="italic">either dies, the other absorbs</text>

    <defs>
      <marker id="faarrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
        <path d="M0,0 L10,5 L0,10 z" fill="#dc2626"/>
      </marker>
    </defs>
  </g>
</svg>
```

The honest costs the roadmap flags: fail-over adds hardware and operational complexity, and there is a real window where data written to the active but not yet replicated is lost when the active dies [1]. That last point is the one I now design around explicitly — the replication lag between active and standby is the maximum data-loss window on failover.

## Replication: copies that stay in sync

Replication is the other redundancy pattern — keeping multiple copies of the same data in different places, so any of them can satisfy a read or take over if another is lost [2][3]. Two structural flavors, with the same master/slave vs master-master names:

- **Master-master.** Multiple nodes accept both reads and writes, coordinating with each other. Any can take over if another fails. The cost is conflict resolution: if two masters accept conflicting writes to the same key simultaneously, something has to reconcile them [2].
- **Master-slave.** One master handles writes and replicates them to read-only slaves. If the master dies, a slave is promoted. Simpler to operate, but the master is a write bottleneck and a single point of write failure until promotion completes [2].

Replication is the pattern that turns a single fragile database into something that survives a node loss without losing the data. Paired with fail-over, it is what makes "promote the slave" a real recovery procedure instead of a hope.

## Reading availability in numbers

The other thing I had to internalize is what an availability percentage actually costs. Availability is measured in "nines" — 99.9% is three nines, 99.99% is four [4]. Each additional nine is an order-of-magnitude reduction in allowed downtime:

And the math for combining components is unforgiving: components **in series** multiply their unavailability (two 99.9% components in series give 99.8%), while components **in parallel** improve it (two 99.9% components in parallel give 99.9999%) [4]. That is the formal justification for redundancy — parallel copies are how you climb the nines ladder.

## How I use this

The habit is to make the budget explicit per service. I name the availability target in nines up front, which forces the redundancy question: how many components fail in series (each must be reliable), and where do I need parallel copies to push the combined number up. For stateful services I always pair replication with fail-over and I name the replication-lag window as the maximum data loss on failover — because "high availability" with silent data loss on promotion is not actually the availability the business thinks it bought.

## References

[1] Serverion, "Active-passive vs. active-active failover," serverion.com, 2023. [Online]. Available: [https://www.serverion.com/uncategorized/active-passive-vs-active-active-failover/](https://www.serverion.com/uncategorized/active-passive-vs-active-active-failover/)

[2] D. Martin, "Replication: availability pattern," system-design-primer (open source), 2024. [Online]. Available: [https://github.com/donnemartin/system-design-primer#replication](https://github.com/donnemartin/system-design-primer#replication)

[3] EnjoyAlgorithms, "Database replication introduction: types and advantages," 2023. [Online]. Available: [https://www.enjoyalgorithms.com/blog/introduction-to-database-replication-system-design](https://www.enjoyalgorithms.com/blog/introduction-to-database-replication-system-design)

[4] EnjoyAlgorithms, "Availability in system design," 2023. [Online]. Available: [https://www.enjoyalgorithms.com/blog/availability-system-design-concept/](https://www.enjoyalgorithms.com/blog/availability-system-design-concept/)

[5] "Uptime calculator: how much downtime corresponds to 99.9% uptime," uptime.is. [Online]. Available: [https://uptime.is/](https://uptime.is/)

[6] DesignGurus, "High availability in system design — 15 strategies for always-on systems," 2023. [Online]. Available: [https://www.designgurus.io/blog/high-availability-system-design-basics](https://www.designgurus.io/blog/high-availability-system-design-basics)

[7] "Design patterns for high availability: what gets you 99.999% uptime?," YouTube, 2020. [Video]. Available: [https://www.youtube.com/watch?v=LdvduBxZRLs](https://www.youtube.com/watch?v=LdvduBxZRLs)

```quiz
Q: In active-passive fail-over, what determines the length of downtime during a failover?
- the cache size on the standby
- whether the passive is hot (already running) or cold (must boot)
correct: 1
explain: A hot standby is already running and can grab the IP quickly; a cold standby has to boot first. The cold-start time dominates the downtime window.

Q: The main residual risk of fail-over, beyond cost and complexity, is…
- the standby is always slower than the active
- data written to the active but not yet replicated is lost if the active dies
correct: 1
explain: Replication lag between active and standby defines the maximum data-loss window on failover. Writes that did not reach the standby are lost when the active dies.

Q: Two components each with 99.9% availability are placed in parallel. The combined availability is…
- lower than 99.9% (parallel hurts)
- higher than 99.9% (parallel helps)
correct: 1
explain: Parallel components improve availability: 1 − (1 − 0.999)² ≈ 99.9999%. Series components multiply their unavailability and hurt.

Q: Master-slave replication is simpler to operate than master-master primarily because…
- there is no write-conflict resolution problem (only the master writes)
- slaves can serve writes too
correct: 0
explain: In master-slave, only the master accepts writes, so there is no concurrent-write conflict to reconcile. The trade-off is that the master is a write bottleneck and a single point of write failure.
```
