Distributed Databases & the CAP Theorem

Distributed database ও CAP theorem

Read: ~45 min Hard 12 practice problems Architecture-heavy

1. Why Go Distributed?

One server has hard limits. A single PostgreSQL box on top-tier hardware peaks somewhere around ~50,000 transactions per second and a few terabytes of working data. The moment a Bangladeshi fintech grows past Dhaka — adding Chattogram, Sylhet and Khulna with low-latency requirements, or surviving a fibre cut in one data centre — a single machine stops being enough. We must replicate data to many machines for durability and read scaling, and partition it across many machines for write scaling and storage capacity. The minute we do, the rules change. This module is the rule-book.

একটি server-এর সীমা আছে — top-tier hardware-এও PostgreSQL সেকেন্ডে ~৫০ হাজার transaction-এর বেশি সামলাতে পারে না। বাংলাদেশের কোনো fintech যখন Dhaka-র বাইরে Chattogram, Sylhet, Khulna-তে কম latency দিতে চায় বা একটি data centre-এর fibre কাটলেও সচল থাকতে চায় — তখন এক machine যথেষ্ট নয়। তাই দরকার replication (একই data একাধিক machine-এ) এবং partitioning / sharding (বড় table-কে অনেক machine-এ ভাঙা)। কিন্তু distributed হলেই অনেক নতুন সমস্যা — সেগুলোই এই module-এ।

2. Replication Strategies

Replication means keeping the same data on multiple nodes. There are three common shapes.

2.1 Leader–Follower (Primary–Replica)

One node — the leader — accepts all writes. It streams a replication log to one or more followers, who apply the same writes in order. Reads can hit either, but if you read from a follower you may see slightly stale data. PostgreSQL streaming replication, MySQL binlog replication, MongoDB replica sets, and Amazon RDS read replicas all follow this pattern.

2.2 Multi-Leader

Multiple nodes accept writes — useful for multi-region setups (a "Dhaka leader" and a "Singapore leader" so users in each region get low-latency writes). The hard part is conflict resolution: what if both leaders simultaneously update the same balance? Last-write-wins, vector-clock merges, or CRDTs are common approaches. CockroachDB, Cassandra (in some modes), and Yugabyte support this.

2.3 Leaderless

No node is special — clients write to several nodes simultaneously and read from several, using quorums to make the result consistent. Dynamo, Cassandra, Riak, and DynamoDB are leaderless or quorum-based.

Leader–follower: এক leader সব write নেয়, follower-রা log apply করে — PostgreSQL, MySQL, MongoDB এই model। Multi-leader: একাধিক leader একসাথে write নেয়, conflict resolve করতে হয় — multi-region-এ কাজে লাগে। Leaderless: সব node সমান, client একাধিক node-এ write/read করে, quorum দিয়ে consistency নিশ্চিত হয় — Cassandra, DynamoDB।
Leader–Follower Leader Follower Follower Multi-Leader Leader-A Leader-B Follower Follower Leaderless (Quorum) N1 N2 N3 client writes to W of N nodes; reads from R; W+R>N Figure 37.1 — Three replication topologies. Each is a different sweet spot in the latency / consistency / availability triangle.

3. Sharding / Partitioning — Splitting One Table Across Many Machines

Replication makes copies. Sharding makes splits. A 4-billion-row order table can be cut into 16 shards of ~250 million rows each, distributed across 16 machines. Three classical strategies:

StrategyHow it worksProsCons
RangeShard 1 = ids 1–10M, shard 2 = 10M–20M …Excellent for range scansHot shards if traffic skews to recent ids
Hashshard = hash(key) mod NEven load, no hotspotsRange scans now hit every shard
DirectoryA separate lookup service: "key X → shard 7"Total flexibility, easy rebalanceLookup service is a new SPOF and extra hop

Consistent hashing is a refined hash strategy that lets you add or remove shards while moving only ~1/N of the keys (instead of all of them). Cassandra, DynamoDB, Riak, and most modern key-value stores use it.

Replication মানে copy, sharding মানে ভাগ। ৪০০ কোটি row-এর order table-কে ১৬টি shard-এ ভাগ করে ১৬ machine-এ রাখা যায়। তিন strategy — range (id 1–10M, 10M–20M …), hash (hash(key) mod N), directory (lookup service)। Consistent hashing হলো এমন একটি hash variant যেখানে shard যোগ-বিয়োগ করলে শুধু 1/N key সরে — পুরো ring rebalance হয় না।
sharding_demo.sql
-- We can't actually shard inside a single SQLite, but we can SIMULATE
-- shard routing: which shard does each key live on for each strategy?

CREATE TABLE orders(id INTEGER PRIMARY KEY, user_id INTEGER, amount INTEGER);
INSERT INTO orders VALUES
    (1,101,500),(2,102,300),(3,103,800),
    (4,104,120),(5,105,990),(6,106,450),
    (7,107,270),(8,108,600);

-- Range sharding by id: shards of width 3
SELECT id, user_id,
       (id-1)/3 AS range_shard,
       user_id % 4     AS hash_shard
FROM orders
ORDER BY id;

4. The CAP Theorem — One Sentence That Shapes Every Distributed DB

Eric Brewer's CAP theorem (2000, formalized by Gilbert & Lynch in 2002) states: in the presence of a network partition, a distributed system can preserve at most one of Consistency (every read sees the latest write) or Availability (every request gets a non-error response). Partition tolerance (P) is not optional — networks fail — so the real choice on a partition is CP or AP.

C — Consistency A — Availability P — Partition tolerance CA, CP, AP (only two at a time during a partition) CP: PostgreSQL with sync replication, MongoDB HBase, Spanner (effectively) AP: Cassandra, Dynamo, CouchDB, Riak Figure 37.2 — CAP Venn. CA without P is only safe if you never expect the network to fail (i.e., one machine).

Worked scenario — bKash transfer during a fibre cut

Imagine bKash runs two replicas: one in Dhaka, one in Chattogram. A fibre cut between them creates a partition. A user in Sylhet sends 500 BDT.

  • CP choice: The Chattogram replica refuses writes until the partition heals — the user sees "transfer failed, please try again". No money is lost, but service is partially unavailable.
  • AP choice: Both replicas accept writes independently. The user sees "transfer successful". When the partition heals, the system must reconcile: what if both sides spent the same 500 BDT? Now you have a double-spend.

Money systems almost always pick CP. Social-feed systems and shopping carts often pick AP — a like that doesn't show up immediately is harmless; refusing every like during a partition is unacceptable.

CAP theorem: network partition হলে distributed system একসাথে Consistency ও Availability — দুটি রাখতে পারে না, যেকোনো একটিকে কোরবানি দিতে হয়। bKash-এর fibre কাটার scenario: CP বেছে নিলে user "transfer failed" দেখবে কিন্তু টাকার হিসেবে কোনো ভুল হবে না; AP বেছে নিলে দু'পাশেই write হবে, পরে reconcile করতে গিয়ে double-spend ঘটতে পারে। টাকার system সবসময় CP — Facebook-এর like হয়তো AP।

5. PACELC — The Honest Extension of CAP

CAP only describes what happens during a partition. But partitions are rare. Daniel Abadi's PACELC (2010) extends it: if Partition (P), choose between Availability (A) and Consistency (C); Else (E), in normal operation, choose between Latency (L) and Consistency (C). Most real production trade-offs are about latency, not partitions.

SystemDuring partitionNormal operationPACELC class
PostgreSQL (sync replication)Refuses writes (CP)Higher write latency for safetyPC/EC
Cassandra (default)Available, possibly stale (AP)Tunable, often favours latencyPA/EL
MongoDB (default)Primary side keeps serving (CP-ish)Reads can hit secondaries (eventual)PC/EL
Google SpannerCP (linearizable)Pays latency for global consistencyPC/EC

6. Consistency Models — A Spectrum, Not a Binary

"Consistent" is not a single thing. There is a whole hierarchy from "the system is one big database" all the way down to "writes propagate eventually". From strongest to weakest:

  • Linearizability / Strong consistency: every operation appears to occur instantaneously at some point between its invocation and response. From the client's perspective the system looks like a single machine. Implemented by Spanner, etcd, ZooKeeper, single-leader RDBMSes with sync replicas.
  • Sequential consistency: all clients see operations in the same global order, but that order is not necessarily real time.
  • Causal consistency: if write A causally precedes write B, every client sees A before B — but unrelated writes may be reordered. CockroachDB, MongoDB causal sessions, COPS.
  • Read-your-writes: a single client always sees its own writes, even if others see older values. The minimum acceptable for "user-friendly" UX.
  • Monotonic reads: a client never goes "backward in time" — once you saw the new value, you never again see the old one.
  • Eventual consistency: if writes stop, all replicas eventually converge. No timing guarantee. Cassandra, DNS, S3 (historically).
"Consistency" এক জিনিস না, একটি spectrum। সবচেয়ে কড়া linearizability (পুরো system যেন এক machine — Spanner, etcd), তারপর causal (cause-effect ক্রম রক্ষা — MongoDB causal session), read-your-writes (নিজের write নিজে দেখা যাবেই — UX-এর minimum), শেষে eventual (write থামালে শেষমেশ converge হবে — Cassandra, DNS)। প্রতিটির জন্য আলাদা trade-off।
Strongest Weakest Linearizable Sequential Causal Read-your-writes Monotonic reads Eventual Spanner CockroachDB most session DBs Cassandra, DNS Figure 37.3 — Consistency spectrum, with rough placements of well-known systems.

7. Quorums — Tunable Consistency in Leaderless Systems

In a leaderless system with N replicas, a write goes to W nodes, a read to R nodes. The crucial inequality is W + R > N: when satisfied, every read overlaps with the latest write on at least one node, so the freshest value is always visible.

SettingN=3Effect
W=1, R=11+1=2 ≤ 3Fastest, weakest. May read stale data. (eventual)
W=2, R=22+2=4 > 3Quorum reads/writes. Strong consistency in normal ops.
W=3, R=13+1=4 > 3Slow writes, fast reads. Good for read-heavy workloads.
W=1, R=31+3=4 > 3Fast writes, slow reads. Good for write-heavy workloads.

Cassandra exposes this exact knob via consistency levels — ONE, QUORUM, ALL, LOCAL_QUORUM (only nodes in the local data centre count), etc.

Leaderless system-এ N replica, write যায় W node-এ, read হয় R node থেকে। যাদুকরী condition: W + R > N। এটি ঠিক থাকলে প্রতিটি read অন্তত একটি node-এ সর্বশেষ write-কে stage করে — fresh value সবসময় দেখা যায়। Cassandra-তে এই knob নাম: ONE, QUORUM, ALL।
cassandra-cql.txt
-- Cassandra CQL: tunable consistency per query (NOT runnable in SQLite)
CONSISTENCY QUORUM;

INSERT INTO payments(user_id, amount, ts)
VALUES (10234, 500, toTimestamp(now()));

CONSISTENCY ONE;            -- speed over freshness
SELECT * FROM payments WHERE user_id = 10234;

CONSISTENCY LOCAL_QUORUM;   -- safe within one data centre, fast across DCs
SELECT * FROM payments WHERE user_id = 10234;

8. Consensus — Paxos and Raft, in 5 Minutes

How does a leader-based replicated system actually elect its leader, or agree on the next entry in the log when the network is unreliable? That problem is called distributed consensus, and it has exactly two famous algorithmic answers: Paxos (Lamport, 1989, infamously hard to read) and Raft (Ongaro & Ousterhout, 2014, deliberately designed to be easy).

Raft in seven lines

  1. Each node is in one of three states: follower, candidate, or leader.
  2. Time is divided into numbered terms; at most one leader per term.
  3. If a follower hears nothing from a leader for an election timeout, it becomes a candidate, increments its term, and votes for itself.
  4. It asks every other node for a vote. Each node grants at most one vote per term.
  5. The candidate becomes leader if it gets a majority. Otherwise, term times out and someone else tries.
  6. Once leader, it sends heartbeats and replicates log entries; an entry is committed when a majority of nodes have stored it.
  7. If a leader is partitioned away, a new leader will be elected on the majority side; the old leader cannot commit anything because it lacks majority votes — safety is preserved.

Production users: etcd (Kubernetes' brain), Consul, CockroachDB, TiKV, RethinkDB, MongoDB's replica election (Raft-derived), and many in-house replication layers.

Distributed system-এ একাধিক node কীভাবে একই সিদ্ধান্তে পৌঁছায়? এই সমস্যার নাম consensus। দুটো বিখ্যাত algorithm: Paxos (Lamport, ১৯৮৯ — পড়তে কঠিন) এবং Raft (২০১৪ — ইচ্ছাকৃত সহজ)। Raft-এ প্রতিটি node তিন state-এ থাকে — follower, candidate, leader। Term-ভিত্তিক election; majority vote পেলে leader; majority node-এ লেখা log entry "committed"। etcd, CockroachDB, Consul, MongoDB election — সব এই family-র।
Follower Candidate Leader timeout: start election won majority discover higher term → step down election lost / split Figure 37.4 — Raft state transitions. Add log replication and term numbering, and you have the whole protocol.

9. Choosing for Real Workloads

✅ Strong consistency wins when…

  • Money is involved (bKash, banks, brokerage)
  • Inventory must not oversell (Daraz Black-Friday)
  • Identity / auth (login service)
  • Locks & sequencing (printing job tickets)

⚠️ Eventual consistency wins when…

  • Social feeds, likes, comments
  • Shopping carts (re-pick at checkout)
  • Analytics dashboards (lag is fine)
  • Logs, telemetry, metrics
Rule of thumb
Strong consistency is expensive — choose it where the cost of being wrong is high. Eventual consistency is cheap — choose it where being briefly stale is fine.

ভুল হলে যদি টাকা/মানুষ/আইন জড়িয়ে যায় — strong consistency নিন (PostgreSQL, Spanner, MongoDB primary)। সামান্য পুরোনো data দেখানো গ্রহণযোগ্য হলে — eventual / AP নিন (Cassandra, DynamoDB)।

10. Practice Problems

Most of these are conceptual — distributed systems can't run inside a single SQLite — but each answer includes either a worked walk-through or runnable code.

অধিকাংশ প্রশ্ন conceptual — distributed system এক SQLite-এ চালানো যায় না। তবে প্রতিটি উত্তরে বিস্তারিত walk-through বা runnable code রাখা হয়েছে।
  1. A 5-node cluster is configured with N=5, W=3, R=3. Is it strongly consistent? Justify.
    ৫-node cluster-এ N=5, W=3, R=3 — কি strongly consistent? কেন?
    ✨ Show Answer

    Answer: Yes (within a single data centre, ignoring partitions). W+R = 6 > N = 5, so any read quorum and write quorum share at least one node — meaning every successful read sees the latest write. (Note: this guarantees quorum consistency, not full linearizability — for that you also need read repair / leader-style ordering.)

  2. Compare range sharding vs hash sharding for a table of WhatsApp-like messages keyed on (user_id, ts).
    WhatsApp-জাতীয় message-এর (user_id, ts)-keyed table-এ range vs hash sharding — কোনটা ভালো এবং কেন?
    ✨ Show Answer

    Answer: Hash by user_id: it spreads load evenly because no single user is "hottest", and the typical query "messages for user X newer than ts T" still hits one shard. Range by ts alone would put all today's traffic on one shard — a textbook hot-shard problem. Range by (user_id, ts) with composite is fine but harder to rebalance.

  3. Write a SQL simulation that assigns 1 million synthetic order ids to 8 hash shards and shows the maximum and minimum shard count. Are loads balanced?
    ১০ লাখ synthetic order id-কে ৮টি hash shard-এ ভাগ করে max ও min shard count দেখান। load কি balanced?
    ✨ Show Answer
    ans3.sql
    WITH RECURSIVE g(i) AS (
        SELECT 1 UNION ALL SELECT i+1 FROM g WHERE i < 100000
    )
    SELECT i % 8 AS shard, COUNT(*) AS n
    FROM g
    GROUP BY shard
    ORDER BY shard;

    Each shard receives 12,500 ± a tiny number — because i % 8 is a perfect hash for sequential ids. With real (non-sequential) ids you would see <1% imbalance for any decent hash function.

  4. In CAP terms, classify: PostgreSQL with synchronous replication, Cassandra default, Redis Sentinel, Spanner.
    CAP অনুসারে classify করুন: PostgreSQL synchronous replication, Cassandra default, Redis Sentinel, Spanner।
    ✨ Show Answer
    • PostgreSQL sync replication → CP — refuses writes if a sync replica is unreachable.
    • Cassandra default → AP — every node accepts; conflicts resolved by last-write-wins timestamps.
    • Redis Sentinel → CP-leaning in practice; failover may briefly lose unreplicated writes.
    • Spanner → CP, achieves linearizability globally via TrueTime + Paxos.
  5. Explain in your own words why "CA without P" is a misleading category for any distributed system.
    "CA without P" কেন distributed system-এর জন্য একটি বিভ্রান্তিকর category — নিজের ভাষায় ব্যাখ্যা করুন।
    ✨ Show Answer

    Answer: Networks fail. A "CA without P" system can only exist on a single machine — once nodes communicate over a network, partitions are inevitable, and the system will face the C-vs-A choice. So in practice every distributed system is either CP or AP; CA is just a single-node DB.

  6. Define read-your-writes consistency and give an example where violating it would confuse users.
    Read-your-writes consistency কী? এটি না থাকলে user কেমন বিভ্রান্ত হবে?
    ✨ Show Answer

    Answer: A client always sees the effects of its own previous writes. Without it: a user updates her bKash profile photo, refreshes, and the old photo is back — because the read landed on a not-yet-replicated follower. Solution: pin reads to the same primary or use a session token (e.g., MongoDB causal sessions).

  7. Sketch how a Raft cluster of 5 nodes survives the loss of any 2 nodes but cannot survive losing 3.
    ৫-node Raft cluster যেকোনো ২ node হারিয়ে কীভাবে টিকে থাকে এবং ৩ হারালে কেন থামে — ব্যাখ্যা করুন।
    ✨ Show Answer

    Answer: Raft commits an entry only when a majority (⌈N/2⌉+1 = 3 of 5) acknowledges it. Lose 2 → 3 healthy → still a majority → keeps committing. Lose 3 → only 2 healthy → no majority → no leader can be elected and no entry can be committed. The cluster pauses (preserving safety) until a third node returns.

  8. Given a 4-billion row order log that is queried mostly by WHERE order_id = ?, design a sharding scheme. How many shards, what key, and why?
    ৪০০ কোটি row-এর order log, query mostly order_id দিয়ে — sharding scheme design করুন।
    ✨ Show Answer

    Answer: Hash-shard by order_id across (say) 32 shards: ~125M rows each, perfectly balanced, every point lookup hits exactly one shard. Use consistent hashing so adding a 33rd shard moves only ~3% of keys. Add an asynchronous secondary index (or column-store sink) for analytics queries that aren't keyed on order id.

  9. PACELC: classify a system you use every day (e.g., DNS, Gmail, BillDesk).
    প্রতিদিন ব্যবহার করেন এমন একটি system (DNS, Gmail) PACELC-এ classify করুন।
    ✨ Show Answer

    Answer (DNS): PA/EL — partition tolerant, available even when name servers can't reach each other (resolvers cache stale entries), and even in normal operation it favours latency over consistency (TTL-based caching, propagation delay). That is exactly the right trade-off for "what IP is google.com?" but the wrong trade-off for "did my payment go through?"

  10. In a leaderless system with N=3, can you tune R and W such that writes are very fast but reads are still consistent? Explain trade-off.
    N=3 leaderless system-এ এমনভাবে R, W set করতে পারবেন যাতে write খুব দ্রুত কিন্তু read consistent থাকে?
    ✨ Show Answer

    Answer: Yes — set W=1, R=3. Writes touch only 1 node so they are fast; reads touch all 3 and pick the most recent value, satisfying W+R > N. The cost: reads are now slow and require all replicas to be up. Useful for write-heavy logging where fresh reads are rare.

  11. Why can a multi-leader topology cause double-spends, and how do real systems mitigate it?
    Multi-leader topology-এ double-spend কেন ঘটতে পারে? real system কীভাবে এটি ঠেকায়?
    ✨ Show Answer

    Answer: Each leader can independently approve a withdrawal because it doesn't see the other's pending writes during a partition. Mitigations: (a) shard the user's account so only ONE leader ever owns that account (eliminates the conflict by construction); (b) use a global consensus layer (Spanner, CockroachDB) that turns the "multi-leader" into per-key Raft groups; (c) accept conflicts and use CRDTs for the small set of operations that commute (counters, sets).

  12. A startup wants strong consistency and global low latency. Is that possible? What is the cost?
    কোনো startup চায় global low-latency এবং strong consistency — সম্ভব কি? খরচ কী?
    ✨ Show Answer

    Answer: Approximately, yes — Google Spanner does it via TrueTime (atomic clocks + GPS) and Paxos per shard. The cost is real money: hardware (atomic clocks in every data centre), engineering complexity, and a hard floor of ~5–10 ms commit latency from the speed of light alone. For most companies the realistic answer is "strong consistency regionally, eventual across regions" — exactly what Aurora Global, Yugabyte, and CockroachDB offer in cheaper deployments.

Summary — Module 37

Going distributed earns scale and durability but introduces choices that no single-machine engineer ever has to make. Replication (leader-follower, multi-leader, leaderless) gives durability and read-scaling. Sharding (range, hash, directory, consistent-hash) gives write-scaling. The CAP theorem — extended by PACELC — frames the inevitable trade-off during partitions and even during normal operation. Within that frame lives a whole spectrum of consistency models, tunable in leaderless systems via the quorum inequality W + R > N. And whenever multiple nodes must agree on a value or a leader, we lean on consensus protocols — Paxos, or its modern, friendlier cousin Raft.

Distributed হলে scale এবং durability পাওয়া যায়, কিন্তু একগাদা কঠিন trade-off আসে। Replication দেয় read-scale, sharding দেয় write-scale, CAP/PACELC ঠিক করে partition-এর সময় কী হবে, consistency model ঠিক করে কতটা পুরোনো data দেখা যাবে, quorum (W+R>N) এই knob-গুলো tune করে, এবং Paxos/Raft দিয়ে node-রা আসল consensus-এ পৌঁছায়। প্রতিটি বাছাই-এর behind একটি ব্যবসায়িক context থাকে।

Next Module → NoSQL — Key-Value, Document, Wide-Column & Graph databases.