Replication adalah menduplikasi data dari 1 database (primary) ke 1 atau lebih database (replica/standby). Tujuan: high availability (kalau primary down, replica ambil alih) dan scale read (distribute query read ke replica).
Kenapa Replication?
- High Availability (HA) — kalau primary crash/maintenance, replica jadi primary baru (failover). Downtime dari jam → detik.
- Read scaling — 90% traffic aplikasi biasanya read-heavy. Route read ke replica, write ke primary.
- Geographic distribution — replica di region berbeda untuk user yang jauh (Asia, EU, US).
- Backup tanpa ganggu primary — backup dari replica, primary tetap cepat.
Streaming Replication (PostgreSQL Default)
Primary kirim WAL (Write-Ahead Log) ke replica secara real-time. Replica apply WAL → state-nya selalu sinkron dengan primary.
┌─ Primary ─┐ ┌─ Replica 1 ─┐
│ Write │── WAL ──→ │ Apply WAL │ (read-only)
│ Read │ └──────────────┘
│ │ ┌─ Replica 2 ─┐
│ │── WAL ──→ │ Apply WAL │ (read-only)
└───────────┘ └──────────────┘
Synchronous vs Asynchronous Replication
Trade-off kunci: konsistensi vs performa.
| Synchronous | Asynchronous | |
|---|---|---|
| Write latency | Tinggi (tunggu replica ack) | Rendah (fire-and-forget) |
| Data loss risk | Nol | Detik terakhir bisa hilang |
| Throughput | Turun 10–30% | Nyaris full |
| Cocok untuk | Financial, critical data | Most web apps |
Postgres default: async. Enable sync per-replica dengan synchronous_standby_names di postgresql.conf.
Read Replica Pattern
Distribute query di level aplikasi:
// Laravel: config/database.php
"mysql" => [
"read" => [
"host" => ["10.0.0.10", "10.0.0.11"], // replicas
],
"write" => [
"host" => ["10.0.0.1"], // primary
],
"sticky" => true, // SELECT setelah INSERT tetap ke primary (stale read mitigation)
],
Aplikasi otomatis route SELECT ke replica, INSERT/UPDATE/DELETE ke primary.
Masalah #1: Replication Lag
Replica selalu sedikit terlambat vs primary (biasanya <100ms, tapi bisa lompat di bawah beban). Skenario yang bikin pusing:
User submit form → write ke primary
User redirect ke "sukses" page → read dari replica
Replica belum sempat apply WAL → user lihat data lama / 404
Solusi umum:
- Read-after-write dari primary (Laravel
sticky: true) - Session-based routing — user yang baru write, routed ke primary untuk N detik
- Monitor lag:
SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag_seconds; - Alert kalau lag >5 detik
Failover — Ketika Primary Mati
Beberapa approach:
1. Manual failover (OK untuk startup kecil)
- Admin promote replica jadi primary lewat
SELECT pg_promote(); - Update DNS/connection string di aplikasi
- Downtime: 5–15 menit
2. Automatic failover dengan Patroni / RDS Multi-AZ
- Tool monitor heartbeat primary
- Kalau primary unreachable X detik → auto-promote replica
- Downtime: 30–60 detik
- Risk: split-brain (primary lama hidup lagi, jadi 2 primary) — butuh STONITH ("shoot the other node in the head") atau quorum (3+ node).
Replica untuk Laravel/PostgreSQL di Production
Paling simple untuk startup: managed database dengan built-in replication.
- AWS RDS Multi-AZ — auto failover, 2 AZ
- Google Cloud SQL HA — sama
- Supabase, Neon — managed PostgreSQL dengan replica
- PlanetScale — MySQL dengan Vitess
Kalau self-host: Patroni + 3-node cluster + HAProxy/PgBouncer di depan. Lebih kompleks, lebih kontrol.
Checklist
- Minimal 1 replica untuk HA
- Async replication untuk web app umum (sync untuk finansial)
- Monitor replication lag
- Failover strategy tertulis (manual atau automatic)
- Test failover minimal 1x/quarter (jangan menunggu insiden beneran)
- Backup masih tetap diperlukan! Replica bukan pengganti backup (corrupted data di primary akan ikut ter-replica)