Handling Node Outages in Leader-Follower Database Replication: A Tale of Resilience

Understanding the Problem: When Database Nodes Go Dark#
Imagine you're running StreamFlix, a popular video streaming platform serving millions of users globally. Your database powers everything from user authentication to movie recommendations, using a leader-follower replication setup for scalability and reliability.
At 2 AM on Black Friday, disaster strikes. Your primary database server in the US-East data center suddenly becomes unresponsive during peak traffic. Millions of users can't log in, stream videos, or access their watchlists. Every second of downtime costs thousands in revenue and user trust.
Our Mission: Design a bulletproof leader-follower replication system that gracefully handles node failures while maintaining data consistency and minimal downtime.
StreamFlix runs one leader in US-East for writes and three followers for reads. A follower crash is minor, but when the leader fails at 2 AM on Black Friday writes halt until detection (10 to 30 seconds), election, promotion and redirection, with the old leader fenced to avoid split brain. Synchronous replication loses nothing but slows writes, asynchronous is fast but can lose the last ones, so payments go synchronous and history asynchronous.
The Anatomy of Our Streaming Platform#
StreamFlix's Database Architecture:
- Leader Node (Primary): Handles all writes - user signups, viewing history, payment processing
- 3 Follower Nodes (Replicas): Serve read queries - movie catalogs, user profiles, recommendations
- Global Distribution: Nodes spread across US-East, US-West, and Europe for low latency
%% title: StreamFlix database cluster
flowchart TD
subgraph UT["User Traffic"]
W["Write Operations<br/>Signups, Payments"]:::client
R["Read Operations<br/>Browse, Search"]:::client
end
subgraph SC["StreamFlix Database Cluster"]
L@{ icon: "sd:database", label: "Leader Node<br/>US-East<br/>Writes Only" }
F1@{ icon: "sd:database", label: "Follower 1<br/>US-West<br/>Reads" }
F2@{ icon: "sd:database", label: "Follower 2<br/>Europe<br/>Reads" }
F3@{ icon: "sd:database", label: "Follower 3<br/>US-East<br/>Reads" }
end
W --> L
R --> F1
R --> F2
R --> F3
L -.->|"Replication"| F1
L -.->|"Replication"| F2
L -.->|"Replication"| F3
class L core
class F1,F2,F3 storeCrisis Scenarios: When Things Go Wrong#
Scenario 1: Follower Node Crash (The Minor Emergency)#
The Incident: During a popular series finale, Follower 2 (Europe) crashes due to hardware failure. European users start experiencing slower response times.
What Happens:
- Writes Continue Unaffected → New user signups and payment processing remain smooth
- Read Traffic Redistributes → Load balancer redirects European users to other followers
- Replication Queues Build Up → Leader stores pending changes for the crashed follower
Detection & Recovery:
Monitoring Alert: "Follower-EU heartbeat missed - 3 consecutive failures"
Auto-Recovery: Redirect traffic → Restart node → Sync from WAL logs
Recovery Time: 2-5 minutes for full synchronizationScenario 2: Leader Node Failure (The Major Crisis)#
The Incident: Our leader node suffers a catastrophic failure during peak Black Friday traffic. The entire write pipeline is down.
Immediate Impact:
- ❌ All Writes Halt → Users can't sign up, purchase, or update profiles
- ⚠️ Read Inconsistency Risk → Followers may have stale data
- 🔄 Failover Required → Must promote a follower to leader
The Failover Dance:
- Detection (10-30 seconds) → Monitoring detects leader unresponsiveness
- Election Process → Choose the most up-to-date follower as new leader
- Promotion → Selected follower becomes the new write-capable leader
- Traffic Redirection → All applications point to the new leader
- Data Reconciliation → Ensure all followers sync with new leader
%% title: The failover dance
flowchart TD
X(["Leader node fails<br/>all writes halt"]):::bad --> D["Detection · 10-30 seconds<br/>monitoring sees leader unresponsive"]:::service
D --> E["Election process<br/>choose the most up-to-date follower"]:::service
E --> P["Promotion<br/>follower becomes write-capable leader"]:::core
P --> T["Traffic redirection<br/>all applications point to new leader"]:::edge
T --> RC(["Data reconciliation<br/>all followers sync with new leader"]):::okThe Consistency Challenge: Synchronous vs Asynchronous Replication#
The StreamFlix Dilemma#
Payment Processing (Critical): When a user purchases a premium subscription, we cannot lose this transaction data. Missing a payment means lost revenue and angry customers.
Viewing History (Less Critical): If a user's "continue watching" position is slightly behind, it's annoying but not catastrophic.
Two Replication Strategies#
Synchronous Replication: The Safe but Slower Approach#
%% title: Synchronous replication
sequenceDiagram
autonumber
participant U as User
participant L as Leader
participant F as Follower
U->>L: Purchase Premium ($9.99)
L->>F: Replicate transaction
F-->>L: Acknowledge success
L-->>U: Payment confirmed
Note over L,F: Write only completes when<br/>follower confirms receiptStreamFlix Use Case: Payment processing, subscription changes
- ✅ Zero Data Loss → If leader fails, follower has all transactions
- ❌ Higher Latency → Each write waits for follower acknowledgment
- ❌ Availability Risk → Slow followers can block all writes
Asynchronous Replication: The Fast but Risky Approach#
%% title: Asynchronous replication
sequenceDiagram
autonumber
participant U as User
participant L as Leader
participant F as Follower
U->>L: Update watchlist
L-->>U: Success (immediate)
L-)F: Replicate later
Note over L,F: Write completes immediately<br/>Replication happens afterStreamFlix Use Case: Viewing history, recommendations, user preferences
- ✅ High Performance → Writes complete immediately
- ✅ Better Availability → Slow followers don't block operations
- ❌ Potential Data Loss → Recent changes may be lost if leader fails
StreamFlix's US-East leader fails at 2 AM on Black Friday and writes halt for 10 to 30 seconds of detection. With asynchronous replication the most up-to-date follower (Follower 1, writes 1-3) is promoted and write 4, never copied, is lost. With a synchronous US-West standby every confirmed $9.99 payment was already acknowledged by it, so promoting it loses nothing, at the price of slower writes.
Real-World Battle Stories: How Giants Handle Failures#
PostgreSQL: The Manual Hero#
StreamFlix's Payment Database Setup:
# PostgreSQL Streaming Replication Configuration
# postgresql.conf (Leader)
wal_level = replica
max_wal_senders = 3
synchronous_commit = on
synchronous_standby_names = 'payment_replica'
# postgresql.conf + empty standby.signal file (Follower, PostgreSQL 12+)
primary_conninfo = 'host=leader-db port=5432 application_name=payment_replica'Failure Scenario: Leader crashes during payment processing
- Detection: Connection timeouts after 30 seconds
- Recovery: Manual promotion (
pg_ctl promote), or automatic failover with tools like Patroni - Downtime: 2-5 minutes for manual failover
- Data Safety: Synchronous mode ensures zero payment data loss, as long as the synchronous standby is the one promoted
MongoDB: The Automatic Guardian#
StreamFlix's User Data Setup:
// MongoDB Replica Set Configuration
rs.initiate({
_id: "streamflix-users",
members: [
{ _id: 0, host: "leader.db:27017", priority: 2 },
{ _id: 1, host: "follower1.db:27017", priority: 1 },
{ _id: 2, host: "follower2.db:27017", priority: 1 }
]
})Failure Scenario: Primary node becomes unreachable
- Detection: Members heartbeat every 2 seconds; a primary unreachable for 10 seconds (the default
electionTimeoutMillis) triggers an election - Recovery: Automatic election and promotion
- Downtime: MongoDB says the median time to elect a new primary should not typically exceed 12 seconds with default settings (longer with slow networks or app reconnects)
- Consistency: Write concern majority ensures data safety
The Complete Disaster Recovery Playbook#
Phase 1: Preparation (Before Disaster Strikes)#
# Monitoring Setup
alerts:
- replication_lag > 5_seconds
- node_heartbeat_failed > 3_attempts
- disk_space < 10%
# Backup Strategy
full_backup: daily
incremental_backup: hourly
cross_region_backup: enabledPhase 2: Detection (First 30 Seconds)#
- Automated health checks every 2-10 seconds
- Multiple detection methods: heartbeats, connection tests, query timeouts
- Alert escalation to on-call engineers
Phase 3: Response (Next 2-5 Minutes)#
- Follower Failure: Redirect traffic, attempt restart, rebuild if needed
- Leader Failure: Execute failover procedure, promote best follower
- Split-Brain Prevention: Fence old leader to prevent dual-writer scenarios
Phase 4: Recovery (Next 10-30 Minutes)#
- Verify new topology is stable
- Resync failed nodes from backups or WAL logs
- Update application configurations
- Post-incident analysis and improvements
Advanced Patterns for Mission-Critical Systems#
The Hybrid Approach: Best of Both Worlds#
%% title: The hybrid approach
flowchart TD
A(["Write Request"]):::client --> B{"Critical Data?"}
B -->|"Yes"| C["Synchronous Replication"]:::core
B -->|"No"| D["Asynchronous Replication"]:::queue
C --> E["Wait for Acknowledgment"]:::service
D --> F["Immediate Response"]:::service
E --> G(["Confirmed Write"]):::ok
F --> GStreamFlix Implementation:
- Payments, Subscriptions → Synchronous (can't lose money!)
- Viewing History, Preferences → Asynchronous (performance matters)
- User Authentication → Semi-synchronous (balance of both)
Geographic Distribution Strategy#
%% title: Geographic distribution strategy
flowchart LR
E@{ icon: "sd:database", label: "US-East<br/>Leader" } <-->|"sync"| W@{ icon: "sd:database", label: "US-West<br/>Sync Follower" }
W <-.->|"async"| EU@{ icon: "sd:database", label: "Europe<br/>Async Follower" }
class E core
class W,EU store- Regional Writes → Synchronous to nearby follower
- Cross-Ocean → Asynchronous to handle network latency
- Disaster Recovery → Each region can promote local follower
Measuring Success: Key Metrics That Matter#
| Metric | Target | Why It Matters |
|---|---|---|
| RTO (Recovery Time Objective) | < 5 minutes | How quickly service restores after failure |
| RPO (Recovery Point Objective) | < 30 seconds | Maximum acceptable data loss |
| Replication Lag | < 1 second | How far behind followers are |
| Failover Success Rate | > 99.9% | Reliability of automatic promotion |
| False Positive Alerts | < 5% | Quality of monitoring system |
Common Pitfalls and War Stories#
Composite scenarios, each modeled on a real kind of failure; named real incidents are noted where they exist.
The Split-Brain Disaster#
What Happened: Network partition made both leader and promoted follower think they were primary Result: Conflicting writes, data corruption, 4-hour recovery time Prevention: Implement proper fencing and witness nodes Real example: GitHub, October 2018: a 43-second network break let Orchestrator fail over to the West Coast while the East Coast primary held unreplicated writes. Both sides then had writes the other lacked, and service was degraded for 24 hours 11 minutes
The Cascading Failure#
What Happened: Follower failure increased load on remaining nodes, causing them to fail too Result: Complete cluster outage during peak traffic Prevention: Proper capacity planning and circuit breakers
The Backup That Wasn't#
What Happened: Discovered during recovery that backups were corrupted for 2 weeks Result: Massive data loss Prevention: Regular backup testing and multiple redundant copies Real example: GitLab.com, January 2017: after a production database was accidentally deleted, none of its backup mechanisms worked as expected, and about 6 hours of data was lost
Summary: Building Antifragile Database Systems#
Leader-follower replication isn't just about copying data—it's about engineering resilience into the heart of your application. By understanding the trade-offs between consistency and availability, implementing proper monitoring and failover procedures, and learning from real-world battle stories, we can build systems that don't just survive disasters—they thrive through them.
Key Takeaways:
- Design for Failure → Assume nodes will fail, plan accordingly
- Monitor Everything → What you can't measure, you can't improve
- Test Regularly → Practice failover procedures before you need them
- Balance Trade-offs → Choose sync vs async based on data criticality
- Learn from Others → PostgreSQL and MongoDB have solved these problems at scale
The next time disaster strikes your database cluster, you'll be ready with battle-tested strategies that keep your users streaming, your payments processing, and your business running smoothly.
Read it through to close the case.
0/10 sections read. Each one counts after a few minutes of actual reading in it; skipping ahead doesn't. The case closes itself once every section is read.
All case files →Failover drill
2 AM, Black Friday, and StreamFlix's leader just went dark. Pick the follower to promote, put the failover dance in order, route five kinds of writes, and keep split-brain away.
- ~2 MIN
- 4 STEPS · 12 PTS
- SOLVE AT 9/12
- +25 XP
this case in shorts · 1
play them all →One idea from this case in about a minute each, made for your phone.

Discussion