Propagation scheme: how many acknowledgements do we wait for?
This is where the hand-wavy single-node notion of ACID "consistency" finally becomes concrete (25:11, 25:35).
| Scheme | Waits for | Guarantee |
|---|---|---|
| Synchronous / strong consistency | All replicas acknowledge the flush | Once told "committed", any node you read shows the change (25:52) |
| Quorum | A majority (e.g. 2 of 3) | Middle ground; bets that simultaneous failures are rare (28:37, 28:58) |
| Asynchronous / eventual consistency | Nobody | Acknowledge immediately; a read elsewhere may miss the change (26:15, 26:38) |
- Synchronous means the primary stalls: send flush → replica flushes WAL (steal / no-force rules still apply) → acknowledgement → only then tell the application (
27:07,27:37). - Asynchronous failure mode: the primary crashes, a replica is elected primary, and the transaction is simply missing because the flush message never arrived. Always send the flush before the client acknowledgement, or the replica never learns the transaction's fate (
27:53,28:08). - Who uses what: NoSQL systems sit at the eventual-consistency end; classic distributed relational systems — DB2, Oracle, NonStop SQL — use synchronous commit because they will not lose data (
29:13,29:32).
Propagation timing: when do we ship the log records?
- Continuous — emit log records to replicas as soon as queries execute, batching optionally, without waiting for commit. Requires also sending a commit or abort message; on abort the replicas must roll back work they already applied (
30:06,30:45). - On commit — stage all log records at the primary and ship only once the transaction is known to commit; replicas never see uncommitted work and never roll back (
30:45,31:12). - Verdict: continuous wins, because aborts are rare in real workloads (think how rarely a banking or browsing session aborts), so assuming commit and streaming early pays off (
31:29).
Execution model: active-passive vs active-active
Active-passive
- The transaction executes on one node; other replicas passively apply the WAL records it produced (
31:55,32:35). - Note: this is not the same axis as primary-replica vs multi-primary — you can run either execution model under either configuration (
37:08,37:34).
Active-active
- The same transaction runs independently on multiple nodes; no WAL is exchanged. The only message needed is at the end: "did you commit?" "yes, same result" (
32:56,33:19). - Requires determinism. Handling non-determinism: same random seed on both nodes; same transaction timestamp assigned at start — typically by a centralized component that stamps the transaction before dispatching it to all nodes (
33:41,33:58). - What is actually saved (answer to a student question): the end-of-transaction round trip still happens; what is avoided is the intermediate data — updating a billion records means a billion WAL records over the network in active-passive, and none in active-active (
34:23,34:35). - Determinism must be a DBMS guarantee, not an application responsibility: the system must enforce the same serial order on every node and eliminate non-determinism (
35:05,35:48). - Almost no system does this. The named example is VoltDB (based on H-Store, which the lecturer helped build) (
36:18). - It works there because transactions run as stored procedures — an RPC-style call carrying application logic (if-clauses, loops, exceptions) interleaved with SQL, run start to finish server-side, removing client/server timing skew (
36:33,37:08) — and because VoltDB's execution engine is single-threaded per CPU core with serializable ordering, so fixing the arrival order fixes the final state (38:00,38:22).
Which costs more? It depends
- Worked example against active-active:
UPDATE ... SET a = a + 1with no WHERE clause over a billion tuples — every node repeats the billion-record scan, whereas active-passive scans once and ships one log record (39:51). - Worked example for active-active: a simple query performing a billion updates — active-passive must ship a billion log records and wait for acknowledgement, while active-active nodes just finish independently and exchange one "we're done" (
40:19,40:44). - Lower isolation levels break active-active: results then depend on which transactions ran concurrently, which differs per node. "Super hard, nobody does it, not worth it" (
41:17).
Bottom line: almost every system uses active-passive, because it reuses the WAL infrastructure already in place, and most applications neither use stored procedures nor avoid non-determinism (38:39, 40:44, 41:34).