İçeriğe geç
Blog

PostgreSQL Patroni ile yüksek erişilebilirlik: 0 RPO, 30s RTO

Patroni + etcd + HAProxy ile çok node'lu PostgreSQL kümesi tasarımı, otomatik failover, split-brain koruması ve operasyonel pratik.

Tarih
Yazar Murat Haktanır
Okuma süresi 3 dk

PostgreSQL’in temelinde basit bir streaming replikasyon vardır. Yüksek erişilebilirlik (HA) için bunu yöneten bir orkestratöre ihtiyaç duyarsınız: kim primary, primary düşerse kim devralır, eski primary geri geldiğinde nasıl davranır?

Patroni bu işin de-facto standardı. Etcd, Consul veya Kubernetes API’sini DCS olarak kullanır; üretimde 0 RPO + 30s civarı RTO sağlar.

Asgari mimari

                  ┌────────────┐
   App  ─────►   │  HAProxy   │ ─── primary route ──► pg-01 (primary)
                  │  (TCP)     │ ─── replica route ──► pg-02, pg-03 (replicas)
                  └────────────┘
                        │
                        ▼
                  ┌────────────┐
                  │  etcd 3-5  │  ◄── Patroni leader election
                  └────────────┘

Tipik kurulum: 3 PostgreSQL node + 3 etcd node + 2 HAProxy node (keepalived ile VIP).

Patroni konfigürasyonu

/etc/patroni/patroni.yml özet:

scope: mono-prod
namespace: /db/
name: pg-01

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.1.10:8008

etcd3:
  hosts:
    - 10.0.1.20:2379
    - 10.0.1.21:2379
    - 10.0.1.22:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576  # 1 MB
    synchronous_mode: true
    synchronous_mode_strict: false
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_level: replica
        hot_standby: on
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 1024MB
        synchronous_commit: on
        synchronous_standby_names: "ANY 1 (*)"

postgresql:
  listen: 0.0.0.0:5432
  data_dir: /var/lib/postgresql/16/main
  authentication:
    replication:
      username: replicator
      password: ...
    superuser:
      username: postgres
      password: ...

synchronous_mode: true ve synchronous_standby_names: "ANY 1 (*)" kombinasyonu: en az 1 replica commit’i onaylamadan primary commit yapmaz → 0 RPO.

synchronous_mode_strict: false: tüm replica’lar düşerse, primary asynchronous moda düşer (downtime yerine veri-kayıp riski). Strict istiyorsanız true; ama tek-node senaryoda yazma durur.

HAProxy ile bağlantı yönlendirme

listen postgres-primary
  bind *:5000
  mode tcp
  option tcplog
  option httpchk GET /primary
  http-check expect status 200
  default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
  server pg-01 10.0.1.10:5432 check port 8008
  server pg-02 10.0.1.11:5432 check port 8008
  server pg-03 10.0.1.12:5432 check port 8008

listen postgres-replicas
  bind *:5001
  mode tcp
  option httpchk GET /replica
  http-check expect status 200
  balance leastconn
  server pg-01 10.0.1.10:5432 check port 8008
  server pg-02 10.0.1.11:5432 check port 8008
  server pg-03 10.0.1.12:5432 check port 8008

Patroni REST API’si /primary ve /replica endpoint’leri ile node’un rolünü bildirir; HAProxy bu cevaba göre trafiği yönlendirir.

Split-brain önleme

Patroni’nin DCS’siz çalışmaması (etcd majority kaybolursa demote olur) split-brain’i önler. Pratikte 3 önlem:

  1. Etcd majority — odd sayı node (3 veya 5); kayıp olunca quorum hâlâ var.
  2. Patroni TTL — primary lock’ı 30s sonunda yenilemezse kaybeder.
  3. fencing (opsiyonel) — eski primary’yi kapat (STONITH benzeri); pratikte uygulamada zor.

Failover gözlemi

Bir Patroni failover’ı sırasında akış:

  1. t=0 primary node kill -9 postgres.
  2. t≤10s primary lock TTL bitiyor; etcd kaybediyor.
  3. t=10-15s Patroni replica’lardan en az lag’a sahip olanı seçer.
  4. t=15-25s seçilen node pg_promote() çağırır.
  5. t=25-30s HAProxy /primary check geçer; uygulamadan yeni primary’ye yazma akar.

RTO ≈ 30 saniye. Uygulama tarafında bağlantı havuzu retry yapıyorsa kullanıcı bunu fark etmez.

Eski primary’nin dönüşü

Eski primary geri geldiğinde Patroni:

  • Yeni primary’nin WAL pozisyonunu kontrol eder.
  • Eski primary çok ilerideyse → pg_rewind ile geri sarar.
  • Geri sarılamayacak kadar farklıysa → tam re-init (basebackup).

pg_rewind ile genelde 30-60 saniyede replica olarak geri girer.

Yaygın hatalar

  • Etcd 1 node. Tüm hassasiyeti tek node’a bağlamak; quorum yok = HA yok.
  • synchronous_mode kapalı + 0 RPO bekleyen müşteri. Ya beklenti netleştirilmeli ya synchronous açılmalı.
  • HAProxy single point of failure. Keepalived + VIP veya 2 HAProxy + DNS-RR.
  • Patroni REST kapanmış. Health check’i Patroni’nin pgsql portu yerine REST’inden yapın.

Mono’nun pratiği

8+ kurulumumuzda son 24 ayda:

  • Ortalama failover süresi 25 saniye.
  • Sıfır veri kaybı (synchronous_mode + replica monitoring).
  • Aylık tatbikat ile primary kapatma + recovery doğrulama.

Sıradaki adımlar

PostgreSQL HA + DR planlaması için, Özgür yazılım veritabanı dönüşümü hizmetimizin bir parçası olarak 1 haftalık ücretsiz keşif çalışması yapıyoruz.

veritabanıoperasyon