Membangun Kluster High Availability PostgreSQL dengan Patroni, etcd, dan HAProxy
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap infrastruktur web modern, database relasional seperti PostgreSQL sering kali menjadi single point of failure (SPOF) utama. Ketika aplikasi web berkembang dari skala ratusan request per detik (RPS) menjadi puluhan ribu RPS yang didorong oleh arsitektur mikroservis, backend Go atau Node.js, serta integrasi frontend Single Page Application (SPA), ketersediaan tinggi (high availability) bukan lagi sekadar opsi tambahan, melainkan mandat arsitektural yang mutlak.
Secara historis, kegagalan master database memaksa administrator sistem untuk melakukan manual failover. Proses ini melibatkan deteksi anomali, eskalasi, promosi replika sekunder menjadi master secara manual, dan pembaruan konfigurasi DNS atau string koneksi pada aplikasi web. Pendekatan ini menghasilkan Recovery Time Objective (RTO) yang bisa memakan waktu belasan hingga puluhan menit, menyebabkan kerugian finansial masif dan rusaknya pengalaman pengguna akhir.
[!WARNING] Melakukan failover database secara manual di tengah malam saat insiden terjadi adalah resep pasti untuk human error, seperti salah mempromosikan replika yang mengalami replication lag tinggi, yang berakibat pada hilangnya data kritikal (split-brain scenario).
Sebelum penerapan kluster High Availability otomatis berbasis Patroni dan etcd, arsitektur umumnya menggunakan skrip shell kustom yang memantau status kesehatan database menggunakan ping atau pengecekan port sederhana. Pendekatan usang ini rentan terhadap false positive akibat fluktuasi jaringan sesaat. Selain itu, manajemen state replikasi ditangani secara manual melalui konfigurasi postgresql.conf dan pg_rewind yang rapuh.
Setelah adopsi arsitektur modern berbasis Patroni, etcd, dan HAProxy, ekosistem berubah drastis:
- Sebelumnya: RTO memakan waktu 10-30 menit; RPO berisiko tinggi hilang karena split-brain; manajemen koneksi aplikasi rumit karena harus mengubah string koneksi saat master berganti.
- Sesudahnya: RTO terpangkas menjadi di bawah 10 detik; RPO mendekati nol (synchronous/asynchronous replication yang terkelola); HAProxy secara transparan merutekan traffic tulis ke master aktif dan traffic baca ke read replica tanpa perubahan baris kode pada backend aplikasi.
2. Konsep Inti & Deep Dive Arsitektur
Untuk memahami bagaimana kluster ini beroperasi, kita harus membedah tiga komponen utama: PostgreSQL sebagai engine database, Patroni sebagai templat manajemen template-driven high availability, dan etcd sebagai distributed consensus store.
Alur Konsensus etcd & Patroni
etcd menggunakan algoritma konsensus Raft untuk memastikan bahwa sekelompok node (biasanya berjumlah ganjil seperti 3 atau 5 node) selalu memiliki satu source of truth yang konsisten. Patroni memanfaatkan etcd untuk menyimpan leader key (kunci kepemimpinan). Node PostgreSQL yang berhasil mengklaim kunci ini dalam etcd dengan TTL (Time To Live) tertentu akan dipromosikan menjadi master.
+-------------------------------------------------------------------------+
| KLIEN / APLIKASI |
+-------------------------------------------------------------------------+
|
v
+-------------------------------------------------------------------------+
| HAProxy (Load Balancer) |
| (Port 5000: Write ke Master | Port 5001: Read ke Replica) |
+-------------------------------------------------------------------------+
| |
v v
+-----------------------------------+ +---------------------------------+
| Node 1 (Master) | | Node 2 (Replica) |
| PostgreSQL + Patroni Daemon | | PostgreSQL + Patroni Daemon |
+-----------------------------------+ +---------------------------------+
^ ^
|------------ Sinkronisasi -------------|
|
v
+---------------------------------+
| etcd Consensus Cluster |
| (Menyimpan Leader Key & State)|
+---------------------------------+
Under the Hood: Mekanisme Heartbeat dan Failover
- Lease & TTL: Patroni daemon pada setiap node secara berkala memperbarui (renew) TTL pada kunci kepemimpinan di etcd.
- Network Partition (Split-Brain Prevention): Jika node master mengalami gangguan jaringan dan gagal memperbarui TTL, kunci tersebut akan kedaluwarsa di etcd.
- Election: Node replika sehat lainnya akan mendeteksi hilangnya kunci kepemimpinan, berkoordinasi melalui Raft consensus di etcd, dan salah satu node akan sukses menulis kunci baru atas namanya.
- Promotion: Patroni daemon pada node pemenang mengeksekusi perintah internal PostgreSQL (
pg_ctl promote) untuk mengubah status database dari read-only replica menjadi read-write master. - Routing Update: HAProxy secara dinamis memeriksa status kesehatan (health check endpoint) yang disediakan oleh Patroni pada setiap node, sehingga traffic aplikasi langsung dialihkan ke master baru dalam hitungan detik.
3. Perbandingan Komparatif / Analisis Pendekatan
Berikut adalah analisis perbandingan antara tiga pendekatan High Availability PostgreSQL yang populer di industri:
| Parameter | Patroni + etcd + HAProxy | Repmgr (Replication Manager) | Pacemaker + Corosync + Stonith |
|---|---|---|---|
| Kompleksitas Setup | Sedang | Rendah | Sangat Tinggi |
| Kecepatan Failover (RTO) | Sangat Cepat (< 10 detik) | Sedang (15 - 60 detik) | Cepat, namun rentan split-brain jika salah konfigurasi |
| Penyimpanan State | etcd (Distributed KV Store) | PostgreSQL Catalog / Witness Node | Corosync Cluster Membership |
| Otomasi & Pemulihan | Sangat Otomatis via API REST | Memerlukan skrip tambahan | Kompleks, butuh agen eksternal FENCE |
| Konsumsi Sumber Daya | Ringan (Go/Python daemon + etcd) | Sangat Ringan | Berat (Overhead Corosync/Pacemaker) |
| Rekomendasi Skala | Cloud-native, Kubernetes, Bare-metal | VPS skala kecil, monolitik | Enterprise legacy berbasis fisik |
[!TIP] Gunakan Patroni untuk hampir semua arsitektur modern karena integrasinya yang sangat mulus dengan konsensus KV store modern seperti etcd atau Consul, serta kemampuannya mengelola konfigurasi PostgreSQL secara terpusat.
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum memulai instalasi, pastikan Anda menyiapkan tiga unit server (atau Virtual Machine) yang berada dalam satu jaringan lokal dengan spesifikasi minimal:
- OS: Ubuntu 22.04 LTS / Debian 12
- RAM: Minimum 2 GB (Disarankan 4 GB+ untuk produksi)
- CPU: 2 vCPU+
- IP Address Contoh:
db-node-1:192.168.1.10db-node-2:192.168.1.11db-node-3:192.168.1.12haproxy-node:192.168.1.20(Bisa digabung dengan load balancer sekunder atau Keepalived)
Persiapan Resolusi DNS Lokal (/etc/hosts)
Tambahkan baris berikut pada /etc/hosts di semua node:
192.168.1.10 db-node-1
192.168.1.11 db-node-2
192.168.1.12 db-node-3
192.168.1.20 haproxy-node
5. Panduan Implementasi Langkah demi Langkah
Langkah 1: Instalasi etcd pada Tiga Node
Lakukan perintah ini di db-node-1, db-node-2, dan db-node-3. Sesuaikan variabel ETCD_NAME dan ETCD_INITIAL_ADVERTISE_PEER_URLS untuk setiap node.
sudo apt update && sudo apt install -y etcd-server etcd-client
Hentikan layanan etcd default untuk menyunting konfigurasinya:
sudo systemctl stop etcd
Sunting file /etc/etcd/etcd.conf.yml (atau buat baru jika menggunakan versi biner langsung) dengan konfigurasi berikut untuk db-node-1:
name: 'db-node-1'
data-dir: '/var/lib/etcd/db-node-1.etcd'
listen-peer-urls: 'http://192.168.1.10:2380'
listen-client-urls: 'http://192.168.1.10:2379,http://127.0.0.1:2379'
initial-advertise-peer-urls: 'http://192.168.1.10:2380'
advertise-client-urls: 'http://192.168.1.10:2379'
initial-cluster: 'db-node-1=http://192.168.1.10:2380,db-node-2=http://192.168.1.11:2380,db-node-3=http://192.168.1.12:2380'
initial-cluster-token: 'etcd-postgres-cluster'
initial-cluster-state: 'new'
(Catatan: Pada db-node-2, ganti semua IP 192.168.1.10 menjadi 192.168.1.11 dan nama node menjadi db-node-2. Lakukan penyesuaian serupa untuk db-node-3).
Nyalakan dan aktifkan layanan etcd:
sudo systemctl daemon-reload
sudo systemctl enable etcd
sudo systemctl start etcd
Verifikasi kesehatan etcd:
etcdctl endpoint health
Langkah 2: Instalasi PostgreSQL dan Patroni
Lakukan langkah ini di ketiga node database (db-node-1, db-node-2, db-node-3).
sudo apt install -y postgresql-15 postgresql-client-15 python3-pip python3-psycopg2 python3-yaml
sudo systemctl stop postgresql
sudo systemctl disable postgresql
Instal Patroni menggunakan pip:
sudo pip3 install patroni[etcd3]
Langkah 3: Konfigurasi Patroni
Buat direktori konfigurasi Patroni:
sudo mkdir -p /etc/patroni
sudo chown -R postgres:postgres /etc/patroni
Buat file konfigurasi /etc/patroni/patroni.yml di db-node-1:
scope: pg-cluster
namespace: /service
name: db-node-1
restapi:
listen: 192.168.1.10:8008
connect_address: 192.168.1.10:8008
etcd3:
hosts:
- 192.168.1.10:2379
- 192.168.1.11:2379
- 192.168.1.12:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 200
shared_buffers: 256MB
listen_addresses: '*'
wal_level: replica
max_wal_senders: 10
max_replication_slots: 10
hot_standby: 'on'
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 192.168.1.0/24 md5
- host all all 0.0.0.0/0 md5
postgresql:
listen: 192.168.1.10:5432
connect_address: 192.168.1.10:5432
data_dir: /var/lib/postgresql/15/main
bin_dir: /usr/lib/postgresql/15/bin
admin_username: postgres
admin_password: secure_postgres_password
replication:
username: replicator
password: secure_replication_password
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
(Catatan: Sesuaikan IP address dan name pada node db-node-2 dan db-node-3).
Langkah 4: Membuat Systemd Service untuk Patroni
Buat file /etc/systemd/system/patroni.service di semua node database:
[Unit]
Description=Patroni orchestrator for 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 dan jalankan Patroni:
sudo systemctl daemon-reload
sudo systemctl enable patroni
sudo systemctl start patroni
Periksa status kluster dengan utilitas PatroniCTL (jalankan di salah satu node):
patronictl -c /etc/patroni/patroni.yml list
Langkah 5: Konfigurasi HAProxy untuk Load Balancing Koneksi
Masuk ke server haproxy-node (192.168.1.20), instal HAProxy:
sudo apt update && sudo apt install -y haproxy
Sunting file konfigurasi /etc/haproxy/haproxy.cfg:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
defaults
log global
mode tcp
option tcplog
option dontlognull
retries 3
timeout queue 1m
timeout connect 10s
timeout client 30m
timeout server 30m
timeout check 2s
# Frontend untuk Koneksi Tulis (Master)
frontend postgres_write_frontend
bind 192.168.1.20:5000
mode tcp
default_backend postgres_write_backend
backend postgres_write_backend
mode tcp
option httpchk GET /primary
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server db-node-1 192.168.1.10:5432 maxconn 200 check port 8008
server db-node-2 192.168.1.11:5432 maxconn 200 check port 8008
server db-node-3 192.168.1.12:5432 maxconn 200 check port 8008
# Frontend untuk Koneksi Baca (Replica)
frontend postgres_read_frontend
bind 192.168.1.20:5001
mode tcp
default_backend postgres_read_backend
backend postgres_read_backend
mode tcp
balance roundrobin
option httpchk GET /replica
http-check expect status 200
default-server inter 3s fall 3 rise 2
server db-node-1 192.168.1.10:5432 maxconn 200 check port 8008
server db-node-2 192.168.1.11:5432 maxconn 200 check port 8008
server db-node-3 192.168.1.12:5432 maxconn 200 check port 8008
# Haproxy Stats Dashboard
listen stats
mode http
bind 192.168.1.20:7000
stats enable
stats uri /
stats refresh 5s
stats auth admin:SecureStatsPassword123
Nyalakan ulang layanan HAProxy:
sudo systemctl restart haproxy
sudo systemctl enable haproxy
6. Bedah Kode & Penjelasan Detail Baris Kunci
Mari kita bedah beberapa parameter krusial dalam file konfigurasi di atas:
ttl: 30&loop_wait: 10(Patroni DCS): Parameterttlmendefinisikan masa berlaku kunci kepemimpinan di etcd. Jika master gagal mengirimkan heartbeat selama 30 detik, etcd akan melepaskan kunci tersebut.loop_waitmenentukan seberapa sering Patroni daemon melakukan pengecekan status internal (setiap 10 detik).use_pg_rewind: true: Ketika mantan master pulih setelah terjadi failover, node tersebut biasanya berada pada posisi timeline WAL yang berbeda dengan master baru.pg_rewindmengizinkan node yang tertinggal untuk melakukan sinkronisasi ulang dengan cepat tanpa harus melakukan basebackup secara penuh dari awal.http-check GET /primary&/replica(HAProxy): Patroni secara otomatis menyediakan REST API endpoint pada port 8008. Endpoint/primaryhanya mengembalikan HTTP status200 OKjika node tersebut sedang berstatus sebagai Master. Sebaliknya, endpoint/replicamengembalikan200 OKjika node berstatus Replica. Ini memastikan HAProxy tidak pernah salah merutekan query tulis ke read replica.on-marked-down shutdown-sessions: Baris ini pada backend tulis HAProxy memastikan bahwa jika node master mati atau terdeteksi down, seluruh koneksi aktif yang macet pada node tersebut akan langsung diputus (killed), memaksa aplikasi backend untuk melakukan reconnect ke master baru yang telah dipromosikan.
7. Skenario Produksi & Studi Kasus Dunia Nyata
Dalam lingkungan produksi berbeban tinggi (misalnya sistem e-commerce flash sale dengan 50.000 RPS dari backend Go dan PHP-FPM):
- Pemisahan Traffic (Read/Write Splitting): Aplikasi dikonfigurasi menggunakan dua koneksi database terpisah. Koneksi utama (Write) diarahkan ke
192.168.1.20:5000(HAProxy master proxy), sedangkan kueri analitik, dashboard, dan laporan dibaca melalui192.168.1.20:5001(HAProxy replica proxy). - Penanganan Beban Lonjakan: Ketika terjadi lonjakan traffic, jika node master mengalami saturasi CPU akibat query berat yang lolos dari optimalisasi indeks, pemantauan Patroni akan mendeteksi peningkatan lag replikasi. Jika melebihi parameter
maximum_lag_on_failover, Patroni mencegah replika bermasalah dipromosikan secara prematur, menjaga integritas data tetap utuh.
8. Common Pitfalls, Anti-Patterns & Solusi
- Anti-Pattern 1: Menggunakan Jumlah Node etcd Genap (2 atau 4 node).
- Dampak: Algoritma konsensus Raft memerlukan kuorum mayoritas ($N/2 + 1$). Pada kluster beranggotakan 2 node, jika 1 node mati, kluster kehilangan kuorum dan etcd menjadi read-only, melumpuhkan seluruh mekanisme failover Patroni.
- Solusi: Selalu gunakan jumlah node etcd ganjil (minimal 3 node).
- Anti-Pattern 2: Mengabaikan Pengaturan
vm.overcommit_memorypada Linux.- Dampak: PostgreSQL membutuhkan alokasi memori yang agresif. Kernel Linux yang ketat dapat menghentikan proses PostgreSQL secara tiba-tiba (Out of Memory Killer) saat beban tinggi.
- Solusi: Tambahkan
vm.overcommit_memory = 2danvm.overcommit_ratio = 80pada/etc/sysctl.conf.
- Anti-Pattern 3: Tidak Mengonfigurasi Firewall (UFW/Firewalld).
- Dampak: Port internal etcd (
2379,2380) atau REST API Patroni (8008) terbuka ke publik, mengundang serangan remote code execution atau manipulasi data kluster. - Solusi: Batasi akses port hanya antar node internal kluster menggunakan UFW:
sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcp sudo ufw allow from 192.168.1.0/24 to any port 2379:2380 proto tcp sudo ufw allow from 192.168.1.0/24 to any port 8008 proto tcp
- Dampak: Port internal etcd (
9. Benchmark, Metrik Kinerja & Tuning Performa
Untuk menguji ketahanan kluster, gunakan tool benchmark standar industri seperti pgbench (bawaan PostgreSQL) atau k6 untuk simulasi beban aplikasi web:
# Inisialisasi data benchmark pgbench sebesar 10GB
pgbench -i -s 100 -h 192.168.1.20 -p 5000 -U postgres postgres
# Jalankan simulasi beban tulis dengan 50 klien konkuren selama 5 menit
pgbench -c 50 -j 4 -T 300 -h 192.168.1.20 -p 5000 -U postgres postgres
Pengujian Failover Otomatis (Chaos Engineering)
Selagi pgbench berjalan mensimulasikan transaksi aktif, lakukan simulasi kegagalan pada node master aktif:
# Matikan layanan Patroni atau restart paksa pada master saat ini
sudo systemctl stop patroni
Amati terminal patronictl list pada node lain. Anda akan melihat proses pemilihan master baru (Leader Election) berlangsung dalam kurun waktu 5 hingga 10 detik, dan pgbench akan melanjutkan transaksi setelah mengalami jeda singkat tanpa mengalami kerusakan data (data corruption).
10. Checklist Penerapan Produksi & Kesimpulan
Sebelum merilis kluster database High Availability ini ke lingkungan produksi yang sesungguhnya, pastikan Anda telah memverifikasi checklist berikut:
- Kluster etcd berjumlah ganjil (3 atau 5 node) dengan latensi jaringan antar node < 5ms.
- Autentikasi sandi yang kuat dan unik diterapkan pada parameter Patroni, PostgreSQL, dan HAProxy.
- Konfigurasi backup otomatis (menggunakan
pg_basebackupatau Barman/PgBackRest) telah terjadwal secara berkala. - Monitoring metrik (Prometheus + Grafana) terpasang untuk memantau status Patroni, penggunaan disk WAL, dan replication lag.
- HAProxy dilengkapi dengan mekanisme Keepalived (Virtual IP) untuk menghindari SPOF pada lapisan load balancer.
Dengan memadukan ketahanan konsensus terdistribusi etcd, otomatisasi orkestrasi cerdas dari Patroni, serta kecepatan perutean koneksi HAProxy, Anda telah membangun fondasi arsitektur data enterprise yang tangguh, andal, dan siap menghadapi skala traffic jutaan pengguna tanpa rasa khawatir.