Synchronous vs. Asynchronous Replication
Wait for replicas to acknowledge writes before confirming to client (sync) or acknowledge immediately and replicate in background (async). Durability vs. latency trade-off.
Intent & Description
🎯 Intent
Balance data durability against write latency by choosing when to replicate data across nodes.
📋 Context
Synchronous replication ensures all replicas have the data before confirming to the client — maximum durability but higher latency. Asynchronous replication confirms immediately and replicates in background — lower latency but risk of data loss if leader fails before replication completes.
💡 Solution
Use semi-synchronous replication (one synchronous replica + async rest) for pragmatic balance. For critical financial data: synchronous within region, async to disaster-recovery site. Monitor replication lag as first-class SLO. Implement appropriate recovery procedures for failover scenarios.
Real-world Use Case
📌 TL;DR
Sync replication = zero data loss, high latency. Async = low latency, data loss risk. Semi-sync = balanced. Choose based on durability requirements vs. latency tolerance.
Advantages
- Synchronous: zero data loss (RPO = 0), strong consistency
- Asynchronous: low latency, high availability
- Semi-synchronous: balanced approach
- Flexible per-operation consistency
Disadvantages
- Synchronous: high latency, reduced availability (slow replica blocks writes)
- Asynchronous: data loss risk (RPO > 0), complexity during failover
- Replication lag monitoring required
- Network partitions cause write failures in sync mode
// Replication Strategies
class ReplicatedDatabase {
async write(key, value, replication = 'semi_sync') {
switch (replication) {
case 'synchronous':
// Wait for all replicas
await this.replicateToAll(key, value);
return { status: 'written', durability: 'maximum' };
case 'semi_sync':
// Wait for primary + one backup
await this.writeToLocal(key, value);
await this.replicateToBackup(key, value);
this.replicateToOthers(key, value); // async
return { status: 'written', durability: 'high' };
case 'asynchronous':
// Write locally, replicate async
await this.writeToLocal(key, value);
this.replicateToAll(key, value).catch(() => {});
return { status: 'written', durability: 'eventual' };
}
}
async getReplicationLag() {
// Monitor lag as SLO
const lags = await Promise.all(
this.replicas.map(r => r.getLag())
);
return Math.max(...lags);
}
}