Back to Advanced: Replication, Consistency, CAP
Q2Question 2 of 5

Common replication topologies and when to use each

Key Concepts
  • Single-primary with read replicas sends all writes to one node and fans reads to replicas for horizontal read scaling.
  • Single-primary keeps writes simple and consistent, with replicas serving as failover candidates.
  • Multi-primary (active-active) accepts writes on more than one node, requiring conflict detection and resolution.
  • Conflict resolution strategies include last-write-wins, per-column merge, and application-level reconciliation.
  • Cascading replication has a replica forward changes to downstream replicas, reducing WAL fan-out load on the primary.
  • Banks avoid active-active for the core ledger because money cannot tolerate conflicting writes.
  • Most systems start single-primary and only adopt multi-primary when multi-region write availability is a hard requirement.

Definition

Single-primary for most apps (simple, read scaling); multi-primary only when you truly need multi-region writes (and accept conflict resolution); cascading to offload fan-out from the primary.
  • Single-primary + read replicas – all writes go to one primary; reads fan out to replicas for scaling; replicas can be promoted on failover.
  • Multi-primary (active-active) – multiple nodes accept writes; requires conflict detection and resolution (last-write-wins, CRDTs, application logic).
  • Cascading replication – a replica forwards changes to downstream replicas, forming a tree that reduces load on the primary.
  • Conflict resolution – the mechanism to reconcile divergent writes when two nodes modify the same row; the hard part of multi-primary.
  • Read-your-writes – a consistency concern with single-primary: a client that writes to the primary and immediately reads from a replica may see stale data.

Single-primary is one National Bank of India head office that records every change and mails copies to branches for reading. Multi-primary is several branches all allowed to write at once: powerful but risky, because two branches might change Rajesh's record differently and you must reconcile. Cascading is a regional hub that receives from head office and relays to its own sub-branches, so head office is not overwhelmed.

Understanding the Concepts

What is single-primary with read replicas?

One writable primary handles all writes. Several read-only replicas serve read traffic and can be promoted on failover. This is the default topology for most applications.

SQL
-- Application connection routing
-- Writes: always go to the primary
UPDATE accounts SET balance = balance - 25000.00
WHERE account_id = 'SAV2001';  -- primary

-- Reads: routed to a replica (round-robin)
SELECT balance FROM accounts
WHERE account_id = 'SAV2001';  -- replica
JAVA
package com.bank.config;

import javax.sql.DataSource;
import java.util.logging.Logger;

public class ReadWriteRoutingConfig {

    private static final Logger LOG = Logger.getLogger(
        ReadWriteRoutingConfig.class.getName());

    private final DataSource primaryDataSource;
    private final DataSource replicaDataSource;

    public ReadWriteRoutingConfig(DataSource primary, DataSource replica) {
        this.primaryDataSource = primary;
        this.replicaDataSource = replica;
    }

    public DataSource getWriteDataSource() {
        LOG.fine("Routing write to primary");
        return primaryDataSource;
    }

    public DataSource getReadDataSource() {
        LOG.fine("Routing read to replica");
        return replicaDataSource;
    }

    public DataSource getReadAfterWriteDataSource() {
        // For read-your-writes consistency, route to primary
        LOG.fine("Read-after-write: routing to primary");
        return primaryDataSource;
    }
}

What are the limits of single-primary?

The limits are replica lag (read-your-writes needs care) and a single write bottleneck. All writes must go through one node, so write throughput is capped by that node's capacity.

TEXT
Single-Primary Limits:

  Writes: all go to one node (bottleneck at high write volume)
  Reads: scale horizontally across replicas
  Lag: replica may be behind by milliseconds to seconds
  Read-your-writes: Rajesh deposits money, then immediately
    reads balance from a replica that has not received the
    write yet. Solution: route read-after-write to primary.

What is multi-primary (active-active) replication?

Multi-primary lets multiple nodes accept writes. This is useful for low-latency writes across regions or continuous availability. The hard part is conflict resolution.

DIAGRAM
Multi-Primary Conflict Scenario:

  Node A (Delhi)              Node B (Mumbai)
  ┌──────────────┐            ┌──────────────┐
  │ UPDATE       │            │ UPDATE       │
  │ Rajesh name  │            │ Rajesh name  │
  │ = 'Raj K.'   │            │ = 'R. Kumar' │
  └──────┬───────┘            └──────┬───────┘
         │       Replicate            │
         └────────────────────────────┘
         CONFLICT: which name wins?
SQL
-- Conflict resolution strategies:

-- 1. Last-write-wins (timestamp-based)
-- The write with the latest timestamp wins
-- Simple but can lose data silently

-- 2. Per-column merge
-- If Node A changed name and Node B changed email,
-- merge both changes (no conflict)

-- 3. Application-level reconciliation
-- Queue conflicting writes for manual or automated resolution

Why do banks avoid active-active for the core ledger?

Money cannot tolerate conflicting writes. If two nodes both debit Rajesh's account simultaneously, the balance can go wrong. Banks prefer single-primary for the ledger and partition writes by region if multi-region is needed.

JAVA
package com.bank.service;

import java.math.BigDecimal;
import java.util.logging.Logger;

/**
 * Why active-active is dangerous for money:
 * Two concurrent withdrawals at different nodes
 * can both succeed, violating the balance invariant.
 */
public class ActiveActiveRisk {

    private static final Logger LOG = Logger.getLogger(
        ActiveActiveRisk.class.getName());

    public void demonstrateRisk() {
        // Node A (Delhi): Rajesh withdraws 80000
        // Node B (Mumbai): Rajesh withdraws 80000
        // Balance: 100000
        //
        // Both nodes check: 100000 >= 80000? Yes.
        // Both nodes debit: 100000 - 80000 = 20000.
        // Replication merges: balance = 20000 on both nodes.
        // But actual withdrawals: 80000 + 80000 = 160000.
        // Real balance should be: 100000 - 160000 = -60000.
        // Money was created out of thin air.

        LOG.severe("Active-active for money is unsafe without "
            + "global coordination (which defeats the purpose)");
    }
}

What is cascading replication?

Cascading replication has a replica act as an upstream for further replicas, forming a tree. This reduces WAL fan-out pressure on the primary when there are many replicas or cross-region hops.

DIAGRAM
Cascading Topology:

  Primary (Delhi)
     │
     ├──► Replica 1 (Delhi local)
     │
     └──► Replica 2 (Mumbai hub)
              │
              ├──► Replica 3 (Mumbai local)
              │
              └──► Replica 4 (Chennai local)

  Primary sends WAL to 2 replicas instead of 4.
  Mumbai hub relays to its own downstream replicas.
SQL
-- PostgreSQL: cascading replication setup
-- Replica 2 connects to Primary
-- primary_conninfo = 'host=primary port=5432'

-- Replica 3 connects to Replica 2 (not Primary)
-- primary_conninfo = 'host=replica2 port=5432'

-- Replica 2 must have hot_standby = on
-- to allow downstream replicas to connect

How do the topologies compare?

| Aspect | Single-Primary | Multi-Primary | Cascading |
|---|---|---|---|
| Write nodes | 1 | Multiple | 1 |
| Conflict risk | None | High | None |
| Read scaling | Good (add replicas) | Good | Good |
| Write scaling | Limited (one node) | Good (multiple) | Limited |
| Complexity | Low | High | Medium |
| Use case | Most apps | Multi-region writes | Many replicas / regions |

When should you use each topology?

Start single-primary and add read replicas. Use cascading when the replica count or geography strains the primary. Adopt multi-primary only when multi-region write availability is a hard requirement and the data model tolerates conflicts.

DIAGRAM
Decision Guide:

  Question                              Topology
  ────────────────────────────────────  ────────────────────
  Standard app, read scaling needed?    Single-primary
  Many replicas, cross-region reads?    Cascading
  Must write in multiple regions?       Multi-primary
  Data is money or has hard invariant?  Single-primary always

What should a senior engineer know?

A senior should know that even "multi-primary" setups in banking often partition writes by region (Delhi accounts write to Delhi, Mumbai accounts write to Mumbai) to avoid conflicts entirely, achieving geographic write locality without true conflict resolution.

DIAGRAM
Partitioned-Write Pattern (bank-safe "multi-region"):

  Delhi Primary          Mumbai Primary
  ┌──────────────┐       ┌──────────────┐
  │ Accounts     │       │ Accounts     │
  │ DEL-*        │       │ MUM-*        │
  └──────────────┘       └──────────────┘
  Writes for Delhi       Writes for Mumbai
  accounts only          accounts only

  No conflict: each account has exactly one writer.
  Cross-region reads via replication for any account.

Visual Overview

DIAGRAM
┌──────────────────────────────────────────────────────┐
│          Replication Topologies                       │
├──────────────────────────────────────────────────────┤
│                                                      │
│  1. SINGLE-PRIMARY + READ REPLICAS                   │
│     ┌──────────┐                                     │
│     │ Primary  │──writes──►                          │
│     └────┬─────┘                                     │
│          ├──► Replica 1 (reads)                      │
│          ├──► Replica 2 (reads)                      │
│          └──► Replica 3 (reads)                      │
│                                                      │
│  2. MULTI-PRIMARY (ACTIVE-ACTIVE)                    │
│     ┌──────────┐    ◄──►    ┌──────────┐             │
│     │ Primary A│ ──conflict──│ Primary B│             │
│     │ (writes) │  resolution │ (writes) │             │
│     └──────────┘            └──────────┘             │
│                                                      │
│  3. CASCADING                                        │
│     ┌──────────┐                                     │
│     │ Primary  │                                     │
│     └────┬─────┘                                     │
│          ├──► Replica 1                              │
│          └──► Replica 2 (hub)                        │
│                   ├──► Replica 3                     │
│                   └──► Replica 4                     │
└──────────────────────────────────────────────────────┘

Key Takeaway

The three common replication topologies are single-primary with read replicas, multi-primary or active-active, and cascading replication. Single-primary sends all writes to one writable node and fans reads to read-only replicas, which keeps writes simple and consistent while scaling reads and giving failover candidates. Its limits are replica lag and the single write bottleneck.

Multi-primary accepts writes on more than one node for multi-region write availability, but it demands conflict detection and resolution because two nodes can change the same row differently. Cascading replication lets a replica forward changes to downstream replicas, offloading fan-out from the primary at the cost of extra lag per hop.

At the National Bank of India, the core ledger is deliberately single-primary because money cannot tolerate conflicting writes. All balance updates go to one writable node and reporting reads are routed round-robin across replicas. For the far region, Pankaj uses a cascading replica that streams from a nearby replica rather than the primary. The team only considers active-active when multi-region low-latency writes are a hard requirement, and even then they partition writes by region to avoid conflicts entirely.

The decision guide is: start single-primary for most workloads, use cascading to relieve fan-out when replica count or geography grows, and adopt active-active only when multi-region writes are mandatory and conflict resolution is acceptable.

Remember one sentence: single-primary for most workloads, cascading to relieve fan-out, and active-active only when multi-region writes are mandatory and conflict resolution is acceptable.

---

Share
Use ← → arrow keys to navigate