Module 14 · Lesson 2 of 8Free
Multi-region architecture: serving users globally
- Level
- Advanced
- Topic
- Multi-region systems and disaster recovery
- Reading time
- 19 min
When you finish this page you can
- Separate request routing from authority to change data.
- Choose regional placement for reads and writes using latency and correctness requirements.
- Trace requests through a multi-region architecture during normal operation and regional failure.
- Calculate the spare capacity needed when one region becomes unavailable.
Builds on 3 lessons
Start with Module 09, lesson 419 minVideo lesson · coming soon
The nearby server still waits
A customer opens from Europe. The page makes three database calls to A in Asia, each paying an assumed 180 ms network round trip.
The team adds an application server in Europe. The page still waits for the same distant database.
How can Kartly serve users near them without giving different regions conflicting versions of an order?
Kartly is at its many-services stage: catalog, cart, orders, payments and search have separate responsibilities. This lesson follows the catalog and order paths, not every service.
All traffic splits, timings and capacities below are illustrative assumptions for this lesson.
A European app server makes three sequential calls to the Asian database. Will moving only the app server make those calls local?Show answer
Diagram not drawn yet: multi-region-remote-data.svg
A European customer reaches a European application through a nearby ingress. The application makes three sequential requests to the authoritative database in Asian Region A. Each database round trip takes an assumed 180 ms, adding 540 ms before processing time.
The useful unit of placement is therefore a request’s dependency path, not an application server. We need to decide which parts of that path can move together.
Place dependencies near the work
A region is a geographic deployment area. A is a set of components that one event can disrupt together.
Putting servers in separate zones addresses some failures within a region. A multi-region architecture also places application capacity and data in separate regions. Google Cloud’s deployment archetype illustrates independent regional application stacks with replicated databases.1
Before adding another region, ask what it must achieve:
| Product question | Kartly’s answer for this scenario | Design consequence |
|---|---|---|
| Must browsing become faster abroad? | Yes | Put catalog reads near customers |
| Can a product description be briefly old? | Yes | Permit local reads |
| Can checkout trust an old stock count? | No | Recheck stock at its |
| Must every region accept orders during isolation? | No | Prefer refusing checkout to overselling |
| Must browsing survive a regional outage? | Yes, with reduced features | Prepare another serving region |
These answers do not imply one architecture for every .
Product images already belong near users through CDNs. An order confirmation has different needs: it must reflect the order that was actually accepted.
The first boundary is between data that may be stale and operations that decide business outcomes. That boundary determines what the second region may do.
Two active apps, one write authority
The simplest correct starting point remains one serving region. It avoids cross-region coordination, but distant users pay network and a regional outage interrupts service.
We will add Region B in Europe. The central question is not whether B runs application servers. It is whether B can independently change the same business data.
What authority should Kartly give the second region?
Active-passive: serve from A and prepare B for recovery.
B holds recovery infrastructure but normally serves no customer requests. This limits normal routing complexity, but European browsing remains distant and the idle path needs regular exercises.
Active applications with local reads and a single writer per shard.
Both regions serve browsing. Each shard retains one write authority in A, so checkout from B crosses regions. This improves local reads without introducing competing writers.
Active writes in both regions.
Each region accepts local writes. Disjoint ownership can make this safe, but shared stock or the same order requires coordination or conflict rules. A local write is no longer automatically an independent write.
Why this choice
Kartly’s immediate problem is distant browsing. It does not require independent checkout during a regional network failure.
Choose local catalog reads in B, with checkout forwarded to the relevant authority in A. Existing shards remain separate; this is not a return to one database for the whole store.
The choice changes if merchants and inventory have disjoint regional ownership. Each region could then own different shards. It also changes if checkout must survive isolation: the product must accept tighter coordination, restricted inventory allocations, or explicitly weaker behavior.
“Active-active” is incomplete unless you name what is active. Here, application serving is active in both regions. A given order shard still has only one writer.
Diagram not drawn yet: multi-region-local-reads-single-writer.svg
Customers reach a global ingress that selects eligible applications in Asian Region A or European Region B. Each application reads its local catalog copy. Region A owns authoritative writes for the illustrated shard. Region B forwards checkout to A. A asynchronously copies committed catalog changes to B. B has no independent write authority.
Give every component a boundary
This diagram shows one shard’s path. Production routing repeats the same authority rule across Kartly’s existing shards.
| Component | Responsibility and connections | State kept | Failure behavior |
|---|---|---|---|
| Global ingress | Select an eligible regional app | Routes and health observations | A bad selection sends users to an unusable region |
| Regional apps | Read local catalog; forward checkout to authority | Short-lived request state | Another region can serve eligible requests |
| Local catalog copy | Answer regional browsing reads | Replicated catalog records | Browsing uses another eligible region or degrades |
| Authoritative store | Validate and commit writes for its shard | Orders, stock and retry records | Checkout stops until authority is safely restored |
| path | Deliver committed changes to B | Progress and retained changes | B becomes progressively stale |
An independently reachable application is not an independent service if every request still calls A.
For this design, browsing must not synchronously contact A for , pricing or configuration. Any dependency left there keeps A on that request’s failure path.
Follow reads and writes separately
Architecture becomes concrete when you can trace one request without guessing.
A catalog read stays local
- The customer connects to the global ingress.
- The ingress selects B because it is eligible and has a better measured network path.
- B’s catalog service reads its local copy.
- B returns the product description and a displayed price.
- Checkout later validates the current price and stock at the authority.
The displayed price is information, not permission to purchase at that price. If validation finds a change, the customer confirms the new price before the purchase proceeds.
A checkout crosses regions
- B receives the checkout request with a .
- B forwards it to the order authority in A.
- The authority validates the request against its authoritative state and runs the existing order workflow.
- It persists the accepted order and retry record before returning success.
- B relays that result to the customer.
B does not turn a timeout into a new order attempt. The client retains the same key, and retries reach the same logical authority.
The immediate confirmation comes from that authoritative result. A later local replica read might not contain the new order yet; read-your-writes consistency covers that separate read-routing requirement.
Copying later changes the guarantee
For a concrete implementation, PostgreSQL 18 streaming replication is asynchronous by default. The primary can commit before changes become visible on a standby.2
That behavior suits our permitted catalog staleness. It does not make B an up-to-date order authority.
PostgreSQL also supports . Depending on configuration, a commit can wait for a standby to durably receive changes or apply them.2
Waiting for B adds a cross-region dependency to acknowledgement. Avoiding that wait leaves a possible gap between acknowledged data in A and data available in B.
We have chosen where requests run. Next we need to verify whether those paths actually meet the latency goal.
Count the regional round trips
Assume a 30 ms round trip between the European customer and B. Assume 10 ms of total local database and application work.
These estimates ignore connection setup and queueing to isolate data placement.
Keep the database distant
30 ms + (3 × 180 ms) + 10 ms = 580 ms
Moving only the application leaves three sequential cross-region calls.
Read a local catalog copy
30 ms + 10 ms = 40 ms
The browsing path removes the regional crossings rather than making them faster.
Forward one checkout request
30 ms + 180 ms + 10 ms = 220 ms
This is a simplified subtotal, excluding payment and other workflow costs. A runs its internal data calls locally.
The checkout boundary matters. B sends one operation to A instead of making several remote database calls itself.
If three reads are independent, running them concurrently may reduce their elapsed network wait toward one round trip. It does not remove the distant dependency or its failure risk.
For this scenario, local browsing is worth deploying B. Local checkout is not yet worth changing data ownership. That leaves request selection as the next decision.
Route by eligibility before latency
The closest region is not always usable. B might answer requests while its catalog copy has stopped advancing.
Define eligibility per operation before selecting the fastest region.
How should Kartly direct requests to regional applications?
Use DNS-based regional selection.
DNS returns a regional endpoint. This is a simple entry point, but clients can retain earlier answers and existing connections do not move when the answer changes.
Use a globally deployed HTTP ingress.
A global proxy selects a regional backend for requests it receives. It can use path-specific eligibility, but adds another dependency and network hop. Its own geographic independence must be checked.
Why this choice
Kartly needs different decisions for browsing and checkout. Choose an HTTP ingress with separate backend eligibility for those paths.
still locates that ingress. The ingress then selects an application region; the application’s authority map selects the writer. Neither selection grants permission to promote a database.
DNS-based routing remains appropriate when coarse regional selection is enough. It avoids proxying application traffic through another layer.
Route 53’s documentation explains that external DNS resolvers cache answers according to their . DNS failover therefore does not immediately change every client’s destination.3
Make eligibility explicit
The ingress owns regional serving eligibility. Order services own the shard-to-authority mapping.
| Operation | Eligible destination | When no destination qualifies |
|---|---|---|
| Catalog browse | App with a readable, sufficiently fresh local catalog | Reduced page or temporary error |
| Checkout reception | App able to reach the approved authority | Temporary error; no success claim |
| Order write | Approved authority for that shard | Stop writes |
| Replica promotion | Never a request-routing decision | Separate recovery procedure |
For this lesson, assume catalog eligibility requires a verified replication heartbeat no older than 30 seconds. Missing evidence makes the region ineligible.
That threshold is a product choice, not a universal value. A stale description is different from a stale emergency notice.
A process-alive probe cannot establish these conditions. The system needs dependency checks and representative customer-path probes. Eligibility must also allow an operator to remove a region deliberately.
Changing traffic is now precise. It still cannot repair missing write authority or missing capacity.
A region disappears, capacity does not
Assume Kartly’s festival peak is 100,000 requests per second. For this exercise, nearly all are browsing requests.
A normally receives 60,000 requests per second. B receives the rest.
Suppose each region has been load-tested to sustain 70,000 requests per second at the required latency.
Observe normal operation
A: 60,000 / 70,000 ≈ 86%; B: 40,000 / 70,000 ≈ 57%
Both regions fit within their tested capacity.
Lose A during the peak
100,000 incoming − 70,000 sustainable = 30,000 excess requests per second
Routing everything to B overloads the surviving region.
Budget for full browsing recovery
100,000 / 70,000 ≈ 1.43 × B’s current tested capacity
B needs that capacity available when recovery traffic arrives, not after users have already overwhelmed it.
For two equally loaded regions, each must normally use no more than half its sustainable capacity to absorb the full combined load immediately.
That statement assumes unchanged request cost and no degraded features. Cold caches or heavier recovery queries can require more capacity.
Autoscaling helps after capacity becomes available. It does not guarantee spare quota, database throughput or fast startup.
Kartly can reserve sufficient browsing capacity, shed optional work, or explicitly accept partial service during failure. Our scenario chooses reduced browsing when full capacity is unavailable.
Refuse checkout without authority
If A becomes unreachable, B may continue eligible catalog reads. Checkout returns a temporary error rather than writing to its replica.
This costs sales, but it respects the product decision against competing stock allocations.
A timeout cannot tell B whether A is dead or merely isolated. Before another store accepts writes, the old authority must be prevented from continuing.
That is a separate recovery operation, covered in Regional failover. A traffic switch alone is not that operation.
Exercise the whole dependency path
A regional exercise should prove a customer outcome, not just a routing change.
| Injected failure | What the customer sees | Evidence and recovery |
|---|---|---|
| B application unavailable | Browsing moves to another eligible region | External probes and regional errors; restore B before readmission |
| Replication to B stops | B eventually loses browse eligibility | Heartbeat age; repair delivery and verify progress |
| A unreachable from B | Checkout temporarily unavailable | Authority-call errors; restore reachability or run controlled recovery |
| Global route points to a bad deployment | Errors across regions | Compare customer probes with regional probes; revert route or deployment |
Keep deployment artifacts, configuration and required credentials available outside A. Otherwise B may serve existing traffic but fail to replace a crashed instance.
Also exercise login, order lookup and payment access. A healthy catalog response does not prove that a customer can complete a purchase.
Independent regions can still share a failure
Regional separation does not isolate a shared bad release, account-wide configuration change or unavailable key service. List these dependencies explicitly rather than treating “two regions” as a complete failure model.
Keep normal request serving separate from administrative changes. A request should use an already available routing and authority configuration, not require a successful deployment API call.
For disjoint regional writers, ownership must cover the contested resource. Assigning customers to regions does not divide a shared stock pool. Moving ownership also requires a controlled handoff.
The remaining question is operational: does the recovery path still work after months of application and configuration changes? Regular exercises are how Kartly finds that answer.
Common mistakes
- Moving applications without their data path. Measure sequential remote calls before expecting lower latency.
- Calling the whole system active-active. State separately where applications serve and where each shard accepts writes.
- Treating a healthy process as a healthy operation. Test the dependencies needed for the advertised behavior.
- Routing writes to whichever region responds. Reachability is not write authority.
- Counting combined capacity only. Check the surviving region under the actual failure workload.
- Testing only browsing. A regional storefront can work while checkout remains unavailable.
Where this shows up
- Design: an e-commerce checkout: stock authority and safe retries must survive regional routing.
- Design: a distributed key-value store: replica placement determines which operations remain possible during isolation.
Kartly can now place requests deliberately; Geo-replication next examines how the second region receives and catches up with its data.
Check your understanding
B serves catalog pages locally but calls A for authentication on every request. Can browsing survive A’s outage?Show answer
The ingress sends checkout to B after A times out. B’s replica is readable. May B accept the write?Show answer
Two regions each handle 40,000 requests per second and can each sustain 60,000. Can one absorb all traffic immediately?Show answer
A product team now requires independent checkout during regional isolation. Is adding another application server enough?Show answer
Summary
- Serve users near them by placing the dependencies their requests need nearby, not just application servers.
- Separate serving regions from write authority; active applications do not require competing writers.
- Route by operation eligibility first and measured latency second.
- Regional recovery needs surviving capacity and a usable dependency path, not only a traffic switch.
- Local replicas can support browsing during isolation without being allowed to accept checkout writes.