High Availability PostgreSQL & Redis Replication untuk Backend SPA
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap arsitektur web modern, Single Page Application (SPA) yang didukung oleh backend terdistribusi (Node.js, Go, PHP-FPM) sangat bergantung pada kecepatan dan ketahanan lapisan data. Ketika sebuah aplikasi SPA mengalami lonjakan trafik, titik kegagalan tunggal (Single Point of Failure / SPOF) pada basis data relasional seperti PostgreSQL atau pada in-memory cache seperti Redis akan langsung melumpuhkan seluruh sistem.
Secara historis, kegagalan paling umum dalam arsitektur backend SPA adalah lonjakan koneksi (connection storm) yang mendadak akibat ribuan klien SPA melakukan polling ulang secara bersamaan saat koneksi WebSocket terputus. Tanpa adanya connection pooling yang efisien, PostgreSQL akan kehabisan proses worker (max_connections), menyebabkan lonjakan latensi (latency spike), dan akhirnya memicu out-of-memory (OOM) killer pada sistem operasi.
Selain itu, ketersediaan tinggi (High Availability) pada lapisan data sering kali gagal diimplementasikan dengan benar. Banyak organisasi mengandalkan replikasi master-slave manual atau skrip bash kustom yang rapuh untuk melakukan failover. Akibatnya, ketika node master PostgreSQL mati, proses pemulihan manual memakan waktu berjam-jam (RTO yang tinggi) dan berisiko kehilangan data transaksi akibat inkonsistensi replikasi asynchronous.
Kondisi Sebelum vs Sesudah Penerapan
| Metrik / Aspek | Sebelum (SPOF / Konvensional) | Sesudah (Patroni HA + Redis Cluster & Pooling) |
|---|---|---|
| Recovery Time Objective (RTO) | 30 - 120 menit (Manual intervention) | < 30 detik (Automated leader election via etcd) |
| Recovery Point Objective (RPO) | Bergantung pada dump terakhir (Potensi kehilangan data) | Mendekati nol (Synchronous/Quorum replication) |
| Kapasitas Koneksi Backend | Langsung ke DB (Raw connection limit terlampaui) | Dimitigasi melalui PgBouncer & Redis Caching Layer |
| Skalabilitas Baca (Read Scaling) | Terbebankan pada satu instance master | Didistribusikan ke multiple replica & Redis cluster |
2. Konsep Inti & Deep Dive Arsitektur
Untuk membangun sistem yang tangguh, kita harus menggabungkan beberapa komponen enterprise: Patroni untuk orkestrasi PostgreSQL HA, etcd sebagai penyimpan konfigurasi terdistribusi dan distributed lock, PgBouncer untuk connection pooling, serta Redis Sentinel/Cluster untuk caching layer berperforma tinggi.
Visualisasi Arsitektur High Availability
+-------------------------------------------------------+
| Single Page Application (SPA) |
+-------------------------------------------------------+
│
▼
+-------------------------------------------------------+
| Nginx Reverse Proxy / Load Balancer |
+-------------------------------------------------------+
│ │
▼ ▼
+-----------------------------+ +-----------------------------+
| Backend Service A (Go/Node) | | Backend Service B (Go/Node) |
+-----------------------------+ +-----------------------------+
│ │ │ │
│ (Pool) │ (Cache) │ (Pool) │ (Cache)
▼ ▼ ▼ ▼
+-------------+ +------------+ +-------------+ +------------+
| PgBouncer | | Redis | | PgBouncer | | Redis |
+-------------+ | Sentinel | +-------------+ | Sentinel |
│ +------------+ │ +------------+
│ │
└────────────────┬────────────────┘
│
▼
+-------------------------------------------------------+
| Patroni Cluster |
| +-------------------+ +--------------------------+ |
| | PostgreSQL Master |◄─┤ PostgreSQL Replica (Sync)| |
| +-------------------+ +--------------------------+ |
| ▲ ▲ |
| └───────────┬──────────────┘ |
| ▼ |
| +-----------+ |
| | etcd | |
| +-----------+ |
+-------------------------------------------------------+
Alur Kerja di Balik Layar (Under the Hood)
- Patroni & etcd: Setiap node PostgreSQL menjalankan agen Patroni. Patroni secara konstan berkomunikasi dengan kluster etcd untuk melakukan leader election. Node yang berhasil memegang lease di etcd akan diinisiasi sebagai PostgreSQL Master. Jika node master berhenti mengirim heartbeat ke etcd, lease kedaluwarsa, Patroni lain akan melakukan pemilihan, mempromosikan replika tersehat menjadi master baru secara otomatis.
- PgBouncer: Berada di antara aplikasi backend dan PostgreSQL. PgBouncer melakukan multiplexing ribuan koneksi klien dari backend menjadi sejumlah kecil koneksi permanen ke PostgreSQL menggunakan mode session, transaction, atau statement pooling.
- Redis Sentinel: Memantau kesehatan master dan slave Redis. Jika master Redis gagal, Sentinel secara otomatis melakukan failover dan memperbarui konfigurasi klien secara dinamis tanpa perlu restart aplikasi backend.
3. Perbandingan Komparatif / Analisis Pendekatan
Dalam merancang lapisan data caching untuk SPA, pemilihan antara Redis Sentinel dan Redis Cluster sangat krusial.
| Parameter Perbandingan | Redis Sentinel | Redis Cluster |
|---|---|---|
| Arsitektur | Master-Replika dengan pemantauan eksternal (Sentinel) | Sharding otomatis terdistribusi tanpa proxy tunggal |
| Kapasitas Penyimpanan | Dibatasi oleh kapasitas RAM satu mesin (Single Node Limit) | Dapat diskalakan secara horizontal (Multi-Node Shards) |
| Kompleksitas Operasional | Rendah hingga Sedang (Mudah di-deploy dan dipantau) | Tinggi (Membutuhkan minimal 6 node: 3 master, 3 replika) |
| Failover Automation | Otomatis via Sentinel Quorum | Otomatis via Gossip Protocol antar node |
| Dukungan Multi-Key Operations | Mendukung penuh semua perintah multi-key | Dibatasi oleh Hash Tags ({user1000}) |
| Rekomendasi Penggunaan | Dataset < 32GB, fokus pada HA dan kemudahan operasional | Dataset masif (> 64GB), kebutuhan throughput ekstrem |
[!TIP] Untuk sebagian besar backend SPA skala menengah hingga besar, Redis Sentinel dikombinasikan dengan pembagian logika aplikasi (application-level sharding) jauh lebih stabil dan mudah di-debug dibandingkan Redis Cluster murni, kecuali Anda mengelola cache berukuran ratusan gigabyte.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum memulai instalasi, pastikan Anda menyiapkan minimal 3 server mandiri (virtual machine atau bare-metal) untuk membentuk kuorum etcd dan Patroni yang andal (aturan kuorum: minimal 3 node untuk mencegah split-brain).
Spesifikasi Minimum Per Node
- OS: Ubuntu 22.04 LTS / Debian 12 / RHEL 9
- CPU: 4 vCPU
- RAM: 8 GB - 16 GB
- Storage: SSD NVMe (IOPS tinggi untuk WAL PostgreSQL)
- Network: Jaringan lokal privat (VPC) dengan latensi < 2ms antar node
Prasyarat Paket & Dependensi
Jalankan perintah berikut pada semua node server:
# Perbarui sistem dan instal dependensi dasar
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y curl vim git jq net-tools lsb-release gnupg software-properties-common
# Nonaktifkan swap untuk performa memori Redis dan PostgreSQL yang optimal
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
# Konfigurasi batas system limit untuk file descriptors
echo "postgres soft nofile 65536" | sudo tee -a /etc/security/limits.d/postgres.conf
echo "postgres hard nofile 65536" | sudo tee -a /etc/security/limits.d/postgres.conf
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Instalasi dan Konfigurasi etcd
etcd bertindak sebagai sumber kebenaran (source of truth) untuk kluster Patroni.
# Instal etcd di ketiga node (Contoh IP: 10.0.1.11, 10.0.1.12, 10.0.1.13)
SUBNET_IP="10.0.1.11"
NODE_NAME="etcd-node-1"
sudo apt-get install -y etcd-server etcd-client
# Buat konfigurasi /etc/etcd/etcd.conf
cat << 'EOF' | sudo tee /etc/etcd/etcd.conf
ETCD_NAME="etcd-node-1"
ETCD_DATA_DIR="/var/lib/etcd/etcd-node-1.etcd"
ETCD_LISTEN_PEER_URLS="http://10.0.1.11:2380"
ETCD_LISTEN_CLIENT_URLS="http://10.0.1.11:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.1.11:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.1.11:2379"
ETCD_INITIAL_CLUSTER="etcd-node-1=http://10.0.1.11:2380,etcd-node-2=http://10.0.1.12:2380,etcd-node-3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF
sudo systemctl restart etcd
sudo systemctl enable etcd
Langkah 2: Instalasi PostgreSQL & Patroni
Instal PostgreSQL dan pustaka Python yang dibutuhkan oleh Patroni.
# Tambahkan repository PostgreSQL resmi
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-15 postgresql-client-15 python3-pip python3-psycopg2 python3-yaml
# Hentikan layanan default agar dikelola oleh Patroni
sudo systemctl stop postgresql
sudo systemctl disable postgresql
# Instal Patroni menggunakan pip
sudo pip3 install patroni[etcd3]
Buat file konfigurasi Patroni /etc/patroni/patroni.yml:
scope: pg-ha-cluster
namespace: /service
name: postgres-node-1
etcd3:
hosts:
- 10.0.1.11:2379
- 10.0.1.12:2379
- 10.0.1.13:2379
restapi:
listen: 10.0.1.11:8008
connect_address: 10.0.1.11:8008
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
synchronous_mode: true
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 500
shared_buffers: 2GB
effective_cache_size: 6GB
maintenance_work_mem: 512MB
work_mem: 16MB
min_wal_size: 1GB
max_wal_size: 4GB
checkpoint_completion_target: 0.9
wal_buffers: 16MB
default_statistics_target: 100
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 10.0.1.0/24 md5
- host all all 127.0.0.1/32 md5
- host all all 10.0.1.0/24 md5
postgresql:
listen: 10.0.1.11:5432
connect_address: 10.0.1.11:5432
data_dir: /var/lib/postgresql/15/patroni
bin_dir: /usr/lib/postgresql/15/bin
pgpass: /var/lib/postgresql/.pgpass
authentication:
replication:
username: replicator
password: SuperSecureReplicationPassword123!
superuser:
username: postgres
password: SuperSecurePostgresPassword123!
saver: true
Buat Systemd service untuk Patroni /etc/systemd/system/patroni.service:
[Unit]
Description=Patroni with PostgreSQL
After=network.target etcd.service
[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no
[Install]
WantedBy=multi-user.target
Aktifkan layanan Patroni:
sudo chown -R postgres:postgres /etc/patroni
sudo systemctl daemon-reload
sudo systemctl enable patroni
sudo systemctl start patroni
Langkah 3: Konfigurasi PgBouncer untuk Connection Pooling
sudo apt-get install -y pgbouncer
Edit /etc/pgbouncer/pgbouncer.ini:
[databases]* = host=127.0.0.1 port=5432 auth_user=postgres
[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
admin_users = postgres
stats_users = monitoring
pool_mode = transaction
max_client_conn = 2000
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 5
reserve_pool_timeout = 5
log_connections = 0
log_disconnections = 0
log_pooler_errors = 1
Buat file otentikasi /etc/pgbouncer/userlist.txt:
"postgres" "md5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"app_user" "md5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
sudo systemctl restart pgbouncer
sudo systemctl enable pgbouncer
Langkah 4: Konfigurasi Redis & Sentinel
sudo apt-get install -y redis-server
Edit /etc/redis/redis.conf (pastikan bind ke IP lokal dan atur password):
bind 0.0.0.0
protected-mode yes
port 6379
requirepass RedisSecretMasterPassword123!
masterauth RedisSecretMasterPassword123!
maxmemory 4gb
maxmemory-policy allkeys-lru
Konfigurasi Redis Sentinel di /etc/redis/sentinel.conf:
port 26379
sentinel monitor mymaster 10.0.1.11 6379 2
sentinel auth-pass mymaster RedisSecretMasterPassword123!
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
sudo systemctl restart redis-server
sudo systemctl restart redis-sentinel
sudo systemctl enable redis-server redis-sentinel
6. Bedah Kode & Penjelasan Detail Baris Kunci
Mari kita bedah beberapa parameter krusial yang terdapat pada konfigurasi di atas:
-
synchronous_mode: true(Patroni DCS):- Fungsi: Memaksa Patroni mengaktifkan replikasi sinkron PostgreSQL. Artinya, transaksi tidak akan dikonfirmasi sukses (commit) oleh master sebelum setidaknya satu node replika menerima dan menulis WAL (Write-Ahead Log) ke disk lokal mereka.
- Dampak Salah Konfigurasi: Jika diatur ke
false(asynchronous), performa tulis sedikit meningkat, namun Anda berisiko mengalami data loss saat terjadi failover mendadak pada master.
-
pool_mode = transaction(PgBouncer):- Fungsi: Menentukan bagaimana PgBouncer mengelola koneksi klien. Dalam mode transaction, koneksi dikembalikan ke pool segera setelah sebuah blok transaksi (
BEGIN...COMMIT) selesai. Ini sangat ideal untuk backend SPA yang mengirimkan ribuan request HTTP singkat secara bersamaan. - Dampak Salah Konfigurasi: Jika menggunakan mode session dengan ribuan koneksi aktif dari Node.js/Go, limit
max_connectionspada PostgreSQL akan cepat tercapai karena koneksi dipegang terus menerus meskipun klien sedang idle.
- Fungsi: Menentukan bagaimana PgBouncer mengelola koneksi klien. Dalam mode transaction, koneksi dikembalikan ke pool segera setelah sebuah blok transaksi (
-
maxmemory-policy allkeys-lru(Redis):- Fungsi: Memberitahu Redis untuk secara otomatis menghapus kunci (eviction) yang paling jarang digunakan (LRU - Least Recently Used) di seluruh kunci yang ada ketika batas RAM (
maxmemory) tercapai. - Dampak Salah Konfigurasi: Jika menggunakan
noeviction, Redis akan menolak perintah tulis baru (OOM command not allowed when used memory > 'maxmemory') yang langsung menyebabkan error pada API backend SPA Anda.
- Fungsi: Memberitahu Redis untuk secara otomatis menghapus kunci (eviction) yang paling jarang digunakan (LRU - Least Recently Used) di seluruh kunci yang ada ketika batas RAM (
7. Skenario Produksi & Studi Kasus Dunia Nyata
Studi Kasus: Sistem E-Commerce Flash Sale dengan 50.000 Konkurensi Pengguna SPA.
- Tantangan: Saat tombol flash sale diklik serentak oleh puluhan ribu pengguna SPA, backend menerima 20.000 request per detik (RPS). Akses langsung ke database relasional untuk memeriksa stok produk akan melumpuhkan PostgreSQL.
- Solusi Arsitektural:
- Caching & Deduplication di Redis: Permintaan cek stok dialihkan ke Redis menggunakan struktur data Hash dan perintah Lua Scripting untuk menjamin operasi atomik pengurangan stok (
DECRBY). - Write-Behind Batching: Backend Go mengumpulkan transaksi pembelian dalam memori (buffer) dan melakukan bulk insert ke PostgreSQL melalui PgBouncer setiap 500ms.
- Read Replicas Scaling: Query pembacaan katalog produk, profil pengguna, dan riwayat transaksi didistribusikan secara round-robin ke node replika PostgreSQL melalui koneksi pool terpisah.
- Caching & Deduplication di Redis: Permintaan cek stok dialihkan ke Redis menggunakan struktur data Hash dan perintah Lua Scripting untuk menjamin operasi atomik pengurangan stok (
8. Common Pitfalls, Anti-Patterns & Solusi
[!WARNING] Anti-Pattern 1: Mengabaikan Network Partition (Split-Brain) pada etcd
- Kesalahan: Menjalankan kluster etcd hanya dengan 2 node.
- Solusi: Selalu gunakan jumlah node ganjil minimal 3 atau 5 node agar algoritma konsensus Raft dapat memilih kuorum mayoritas dengan aman.
[!WARNING] Anti-Pattern 2: Koneksi Database Langsung Tanpa PgBouncer di Lingkungan Serverless/Containers
- Kesalahan: Menghubungkan ribuan kontainer backend Node.js langsung ke port 5432 PostgreSQL.
- Solusi: Selalu arahkan koneksi ke PgBouncer di port 6432. Batasi ukuran pool per instance kontainer agar total koneksi kumulatif tidak melampaui kapasitas server database.
9. Benchmark, Metrik Kinerja & Tuning Performa
Untuk menguji ketahanan kluster yang telah dibangun, gunakan alat load testing seperti k6 atau wrk. Berikut adalah skrip pengujian k6 untuk mensimulasikan trafik SPA:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 500 }, // Ramp-up ke 500 pengguna
{ duration: '2m', target: 2000 }, // Pertahankan 2000 RPS
{ duration: '30s', target: 0 }, // Ramp-down
],
};
export default function () {
const res = http.get('https://api.domain.com/v1/products/featured');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 50ms': (r) => r.timings.duration < 50,
});
sleep(0.1);
}
Parameter Tuning Lanjutan (Kernel Linux /etc/sysctl.conf)
# Optimasi TCP stack untuk koneksi konkurensi tinggi
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Optimasi memori virtual untuk database
vm.swappiness = 1
vm.overcommit_memory = 1
Apply konfigurasi kernel:
sudo sysctl -p
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum meluncurkan infrastruktur ini ke lingkungan produksi publik, pastikan Anda memverifikasi item-item dalam checklist berikut:
- Kluster etcd berjumlah ganjil (3/5 node) dan berjalan stabil dengan latensi < 2ms.
- Patroni aktif dan verifikasi failover otomatis berhasil dilakukan (uji coba matikan node master secara paksa).
- PgBouncer terkonfigurasi dengan mode transaction dan batasan max_client_conn sesuai kapasitas RAM.
- Redis Sentinel memantau master dengan quorum yang benar dan password terautentikasi.
- Firewall (UFW / iptables / AWS Security Groups) membatasi akses port database hanya dari IP internal backend dan PgBouncer.
- Skrip backup otomatis harian (
pg_dump/pg_basebackup) dikonfigurasi dan disimpan ke storage eksternal (S3 / MinIO). - Monitoring metrik (Prometheus & Grafana) terpasang untuk memantau CPU, RAM, IOPS, Replication Lag, dan jumlah koneksi aktif.
Dengan menerapkan arsitektur Patroni HA PostgreSQL dan Redis Sentinel caching layer secara tepat, backend SPA Anda akan memiliki pondasi infrastruktur yang sangat tangguh, skalabel, dan siap menghadapi lonjakan trafik enterprise kelas dunia.