Multi-Region and Disaster Recovery
Surviving the loss of an entire datacenter or region, and serving users across the globe. The most
expensive, complex thing in this book — and the place where CAP stops being theory.
Prerequisites: CAP & PACELC, Replication
Time to read: ~22 minutes
Two problems, often conflated
Multi-region deployment serves two distinct goals, and conflating them causes confused designs:
- Disaster recovery (DR) — survive a whole-region failure (fire, flood, a cloud provider’s region
outage, a botched deploy that takes down a region). Availability.
- Geographic performance — serve users near them, avoiding the
~150ms cross-continent latency. Latency. And sometimes
data residency (compliance) forces it.
🚨 These have different solutions. DR can be a passive standby region; geo-performance needs active
regions serving traffic. Know which problem you’re solving.
And a prior question: 🚨 do you even need multi-region? Multi-AZ already
survives a single-datacenter failure cheaply. Multi-region is a large step up in cost and complexity,
justified by whole-region-failure protection, global latency, or compliance — not by default.
RTO and RPO: the DR vocabulary
🚨 The two numbers that define your DR requirements, and they come up:
- RTO (Recovery Time Objective) — how long can you be down? (Minutes? Hours?)
- RPO (Recovery Point Objective) — how much data can you lose? (The last second? The last hour?)
RTO = downtime tolerance (how fast must you recover)
RPO = data-loss tolerance (how much recent data can vanish)
📐 A payment system might need RTO of minutes and RPO of zero (lose no transactions). A blog might
tolerate RTO of hours and RPO of a day. 🚨 These numbers drive the DR strategy and its cost —
tighter RTO/RPO means more expensive architecture. Ask for them.
DR strategies (the spectrum)
From cheapest/slowest to most expensive/fastest:
1. Backup & restore. Back up to another region; on disaster, restore.
- RTO: hours. RPO: since the last backup (hours).
- ✅ Cheapest. ❌ Slow recovery, significant data loss.
2. Pilot light. A minimal version always running in the standby region (core data replicated, but
compute scaled to zero); scale it up on disaster.
- RTO: tens of minutes. RPO: minutes (data replicated).
- ✅ Cheaper than warm standby. ❌ Some scale-up time.
3. Warm standby. A scaled-down but fully functional copy always running; scale up and shift traffic
on disaster.
- RTO: minutes. RPO: seconds.
- ✅ Fast recovery. ❌ Pay for the standby.
4. Hot standby / active-active. Full capacity in multiple regions, all serving traffic.
- RTO: near-zero. RPO: near-zero (or the replication lag).
- ✅ Instant failover, geo-performance too. ❌ Most expensive and complex.
🎙️ “The strategy follows the RTO/RPO. For an RTO of hours and RPO of a day, backup-and-restore. For an
RTO of minutes and RPO of seconds — a critical service — warm standby or active-active. The tighter the
numbers, the more you pay.”
Active-passive vs active-active
The core architectural choice for a running multi-region system:
Active-passive — one region serves all traffic; the other(s) stand by (warm/hot). On failure,
promote the passive region.
- ✅ Simpler — 🚨 only one region takes writes, so no cross-region write conflicts. The passive
region receives replicated data.
- ❌ The passive region’s capacity is mostly idle (wasted cost), and failover has a window.
Active-active — multiple regions serve traffic simultaneously.
- ✅ Full use of all regions, geo-performance (users hit the nearest), instant regional failover.
- ❌ 🚨 The hard one: writes happen in multiple regions, so you get
write conflicts. This is where
CAP becomes concrete and unavoidable.
🚨 The central challenge of active-active is data. Reads are easy (replicate to every region, read
locally). Writes are hard, because you’re now doing multi-master replication across a
150ms-latency link.
The data problem in active-active
This is the crux, and it’s where the distributed-systems theory pays off:
Option A — single-region writes (write-forwarding). All writes go to one “home” region (per
record or globally); reads are local everywhere. Avoids conflicts, but cross-region writes pay the
latency, and losing the write region needs failover.
Option B — regional write ownership (sharding by region). 🚨 Often the best answer: each record
has a home region (e.g. by user location), and its writes always go there. EU users’ data is written
in the EU, US users’ in the US — no two regions write the same record, so no conflicts. This also
satisfies data residency. Cross-region access is slower
but rare.
Option C — accept conflicts and resolve them. True multi-master; use
CRDTs, vector clocks, or LWW to resolve
concurrent writes to the same record. Powerful but complex, and LWW silently loses data.
Option D — a globally-consistent database. Spanner, CockroachDB, or DynamoDB Global Tables handle
multi-region consistency for you — at the cost of latency (a globally-consistent write pays cross-region
round trips) and money.
🎙️ “For active-active, the hard part is writes. I’d shard by region — each user’s data has a home
region where its writes happen — so no two regions write the same record and there are no conflicts.
That also handles data residency. Truly global writes to one record would need either write-forwarding,
conflict resolution, or a globally-consistent database like Spanner, each with a latency or complexity
cost.”
This region-sharding answer is strong — it sidesteps the conflict problem rather than solving it,
which is the mature move.
Routing traffic to regions
How users reach the right region:
- GeoDNS — DNS returns the nearest region’s IP based on the resolver’s location.
🚨 But DNS failover is slow and unreliable — resolvers cache, so it’s
poor for fast regional failover.
- Anycast — 🚨 the same IP announced from every region; BGP routes each user to the nearest healthy
one, rerouting in seconds on failure with no DNS involvement. This is how CDNs and global load
balancers work, and it’s the good answer for both geo-routing and fast failover.
→ CDN, DNS
- Global load balancers (cloud-managed) — health-check regions and route accordingly.
The things people forget
🚨 DR is only real if it’s tested:
- Test your failover. 🚨 An untested DR plan is not a DR plan. The
GitLab and
S3 incidents both showed that recovery paths not
exercised regularly don’t work when needed. Game days
that actually fail over a region.
- Backups must be tested by restoring them — a backup you’ve never restored is a hope, not a
backup. GitLab’s data loss happened because five backup mechanisms had all silently failed.
- Dependencies must also be multi-region — 🚨 failing over your app to a second region is useless if
its database, its config service, or a critical third party is single-region. The whole dependency
chain must survive.
- Don’t create circular dependencies in recovery — Facebook’s 2021 outage was worsened because the
tools needed to fix the problem depended on the thing that was down.
- Split-brain during regional partition — if regions can’t reach each other, which is authoritative?
Needs consensus/quorum or a clear ownership model.
⚖️ Trade-offs
| Strategy |
RTO |
RPO |
Cost |
Complexity |
| Backup & restore |
Hours |
Hours |
💚 Lowest |
Low |
| Pilot light |
~30 min |
Minutes |
💛 Low |
Medium |
| Warm standby |
Minutes |
Seconds |
🧡 Medium |
Medium |
| Active-active |
~Zero |
~Zero |
🔴 Highest |
High (write conflicts) |
| Choice |
Gain |
Cost |
| Multi-AZ |
Cheap datacenter-failure resilience |
Doesn’t survive region failure |
| Active-passive |
Simpler (single write region, no conflicts) |
Idle standby capacity; failover window |
| Active-active |
Geo-performance, instant failover |
Write conflicts, cost, complexity |
| Region-sharded writes |
No conflicts, residency handled |
Cross-region access is slow/rare |
| Global DB (Spanner) |
Consistency handled for you |
Latency and cost |
In the real world
- Netflix runs active-active across multiple AWS regions and regularly does “Chaos Kong” — failing
an entire region — to prove their multi-region failover actually works. It’s the reference for hot,
tested regional resilience.
- The AWS us-east-1 outages repeatedly demonstrate why region-failure protection matters — an
enormous fraction of the internet depends on one region, and its outages cascade globally. Systems
with real multi-region survive; those without don’t.
- GitLab’s 2017 data loss (five failed backups) and Facebook’s 2021 outage (circular recovery
dependency, badge readers down so engineers couldn’t enter the building) are the canonical lessons
that DR must be tested and recovery must not depend on the thing that’s down.
🚨 Interview traps
- Reaching for multi-region by default — multi-AZ handles datacenter failure cheaply; multi-region
is a big step you justify.
- Not knowing RTO/RPO — the numbers that define DR.
- Conflating DR and geo-performance — different problems, different solutions.
- Ignoring the write-conflict problem in active-active — it’s the crux, and CAP made concrete.
- DNS for fast failover — it’s too slow (caching); anycast/global LB.
- Untested DR — an untested plan doesn’t work.
- Single-region dependencies undermining a multi-region app.
🎙️ Soundbites
- “First, do we need multi-region? Multi-AZ already survives a datacenter failure cheaply.
Multi-region is justified by whole-region-failure protection, global latency, or data residency —
not by default.”
- “The strategy follows RTO and RPO. Hours and a day of data loss → backup-and-restore. Minutes and
seconds → warm standby or active-active. Tighter numbers cost more.”
- “Active-active’s hard part is writes. I’d shard by region — each user’s data has a home region where
writes happen — so no two regions write the same record and there are no conflicts. That also handles
residency. Truly global single-record writes need write-forwarding, conflict resolution, or a global
database like Spanner.”
- “For failover I’d use anycast or a global load balancer, not DNS — DNS caching makes it too slow to
reroute. Anycast reroutes in seconds at the network layer.”
- “An untested DR plan isn’t a DR plan. I’d run game days that actually fail over a region, and test
backups by restoring them — and make sure every dependency is multi-region too, or the failover is
useless.”
🛠️ Try it
1. Define RTO/RPO and pick a strategy. For three systems (a bank, a blog, a game), define RTO and
RPO, then pick the DR strategy each needs. Notice how the numbers drive the choice — and how much
more the tight ones cost.
2. Build active-passive replication. Set up a primary database in one region replicating to a
standby in another. Then simulate a region failure: promote the standby, shift traffic. Time the
failover (your RTO) and check how much data was lost (your RPO). These are your real numbers.
3. Hit the write-conflict problem. In an active-active setup, write to the same record in two
regions simultaneously (during a simulated partition), then heal. Watch the conflict — which write
wins, and does LWW silently lose one? Then implement region-sharded writes and confirm the conflict
disappears (each record has one home region).
4. Test a backup by restoring it. Take a database backup, then actually restore it into a fresh
environment and verify the data is intact and usable. A surprising number of backups fail this —
and finding out in a drill beats finding out during a disaster.
Check yourself
1. What are RTO and RPO, and why do they matter?
They're the two numbers that define your disaster-recovery requirements. **RTO (Recovery Time
Objective)** is how long you can be down — your downtime tolerance, "we must recover within X minutes."
**RPO (Recovery Point Objective)** is how much data you can afford to lose — your data-loss tolerance,
"we can lose at most the last X of data." They matter because together they drive the entire DR
strategy and its cost: a tight RTO (recover in minutes) and RPO of zero (lose no data) demand an
expensive architecture — a hot standby or active-active with synchronous replication — while a loose
RTO (hours) and RPO of a day allow cheap backup-and-restore. A payment system needs RTO of minutes and
RPO of zero (never lose a transaction); a blog tolerates RTO of hours and RPO of a day. Asking for
these numbers is the first step in any DR design, because everything — the strategy, the replication
approach, the cost — follows from them. Building a zero-RPO system for a blog wastes money; building a
day-RPO system for payments loses transactions.
2. Why is multi-AZ often sufficient, and when do you actually need multi-region?
Multi-AZ deployment (spreading across isolated datacenters within one region) already provides cheap
resilience against the most common infrastructure failures — a single datacenter losing power,
cooling, or network — because AZs are separate failure domains close enough for fast synchronous
replication, so an AZ failure leaves your service running in the others with minimal cost or latency
impact. Multi-region is a large step up in cost and complexity (cross-region latency, data
replication challenges, potential write conflicts, doubled infrastructure), so you adopt it only when
multi-AZ isn't enough: to survive a *whole-region* failure (a cloud provider's entire region going
down, which does happen — AWS us-east-1 outages are notorious), to serve users in distant geographies
with low latency (avoiding the ~150ms cross-continent penalty), or because data residency laws require
data to stay in a specific region. If none of those apply, multi-AZ within one region is the right
default, and reaching for multi-region "to be safe" imports enormous cost and complexity for
protection you may not need.
3. Why is active-active fundamentally harder than active-passive?
Because of writes. In **active-passive**, only one region accepts writes; the passive region(s)
receive replicated data and stand by. Since there's a single writer, there are no conflicts — the data
model is straightforward multi-master-free replication. In **active-active**, multiple regions serve
traffic simultaneously, which means writes happen in multiple regions — and now you have multi-master
replication across a high-latency (~150ms) link, where two regions can modify the *same record*
concurrently before they've synchronized. This produces **write conflicts** with no obvious
resolution: which write wins? This is exactly where the CAP theorem stops being theory and becomes an
unavoidable design decision — during a network partition between regions, you must choose between
consistency (reject writes on one side) and availability (accept writes on both and reconcile). Reads
in active-active are easy (replicate everywhere, read locally); it's the writes that force you into
conflict resolution (CRDTs, vector clocks, last-write-wins), write-forwarding to a single region,
region-sharded ownership, or a globally-consistent database — each with real latency, complexity, or
data-loss trade-offs.
4. How does sharding writes by region sidestep the active-active conflict problem?
By ensuring no two regions ever write the *same* record. Instead of allowing any region to write any
record (which creates conflicts when two regions modify the same one concurrently), you assign each
record a *home region* — typically based on the user's location — and route all writes for that record
to its home region. EU users' data is written only in the EU region, US users' only in the US region.
Since a given record has exactly one writer region, concurrent conflicting writes to the same record
can't happen, so there are no conflicts to resolve — you've sidestepped the hard problem rather than
solving it. Reads can still happen locally in any region (data is replicated everywhere for reading),
and the only cost is that *cross-region* access to a record not in your home region is slower — but
that's rare when the sharding matches usage patterns. As a bonus, this naturally satisfies data
residency compliance (EU data physically lives and is written in the EU). It's the mature answer
because it converts a hard distributed-systems problem (conflict resolution across regions) into a
simpler routing problem (send writes to the home region), which is why it's often the best approach for
active-active — you get geo-distributed writes without multi-master conflicts.
5. Why is an untested disaster-recovery plan not actually a disaster-recovery plan?
Because recovery paths that aren't exercised regularly reliably fail when you finally need them, and a
DR plan's entire value is being able to execute it during an actual disaster. The failure modes are
numerous and only surface when tested: backups that have been silently failing for months (GitLab's
2017 data loss happened because *five* separate backup mechanisms had all quietly broken, discovered
only when they urgently needed to restore); failover procedures with wrong or outdated steps; standby
regions missing a critical dependency that's still single-region (so failing over the app is useless
because its database or config service isn't there); recovery tooling that depends on the very system
that's down (Facebook's 2021 outage was worsened because the tools to fix it, and even the building's
badge readers, depended on the failed infrastructure); and capacity in the standby that turns out
insufficient under real load. None of these are visible on paper — the plan looks complete — and all
of them are catastrophic during a real disaster when there's no time to debug them. The only way to
know a DR plan works is to *run* it: game days that actually fail over a region, and restore drills
that actually restore backups into a working environment and verify the data. An unexercised plan is a
hopeful document, not a capability.
Further reading