Patroni là một HA agent cho PostgreSQL, chạy trên mỗi database node và chịu trách nhiệm duy nhất: đảm bảo cluster luôn có đúng một primary. Nó không tự mình quyết định — nó dùng một distributed consensus store (thường là etcd) để đồng thuận với các nodes khác về trạng thái cluster, tránh split-brain.

Cơ chế hoạt động

Patroni dùng Raft consensus thông qua etcd (hoặc Consul, ZooKeeper). Mỗi node Patroni liên tục:

  1. Heartbeat vào etcd để giữ leader lease
  2. Nếu primary mất heartbeat (TTL hết hạn), etcd xóa lock
  3. Các standby nodes race để acquire lock mới — winner promote thành primary
  4. Node thắng update cluster state trong etcd; các node còn lại đọc state và tự cấu hình làm replica

Đây là automatic failover không cần human intervention. Thời gian failover thường 10–30 giây tùy cấu hình ttlloop_wait.

Production Gotchas

Bốn gotcha quan trọng phát hiện qua validation thực tế trên RHOSO:

1. arping callback phải dùng nohup ... & disown

Patroni giết tất cả callback processes vẫn đang chạy sau loop_wait (mặc định 10s). Nếu arping cho VIP failover callback chạy lâu hơn 10s, nó bị kill trước khi hoàn thành:

# ❌ Sai — bị Patroni kill sau 10s
arping -c 5 -I eth0 <VIP>
 
# ✅ Đúng — chạy background, không bị kill
nohup arping -c 5 -I eth0 <VIP> & disown

2. allowed-address-pairs cho VIP phải set trên TẤT CẢ 3 DB VM ports

Neutron security group behavior: nếu VIP chỉ được allowed trên port của primary, traffic từ primary gửi với source VIP sẽ bị drop khi đến replica. Phải set allowed-address-pairs trên cả 3 Neutron ports của DB VMs — nếu không, traffic từ leader mới bị silently drop.

3. Callbacks nằm dưới postgresql: section (không phải root level)

# ❌ Sai
callbacks:
  on_role_change: /path/to/callback.sh
 
# ✅ Đúng
postgresql:
  callbacks:
    on_role_change: /path/to/callback.sh

4. systemctl restart patroni — SIGHUP không reload callbacks

Thay đổi callback config yêu cầu full restart của Patroni service. SIGHUP hoặc systemctl reload không reload callback definitions — chỉ reload PostgreSQL parameters.

etcd v2 API Dependency

python-etcd (thư viện Python client cho etcd) yêu cầu etcd v2 API — phải explicitly enable:

etcd --enable-v2=true

Không có flag này, Patroni không thể kết nối tới etcd cluster. Đây là known limitation của python-etcd (không hỗ trợ v3 gRPC API). Mitigation: thêm --enable-v2=true khi start etcd. Long-term: migrate sang python-etcd3 hoặc etcd3gw.

Patroni vs pgpool Quorum

Pgpool-II cũng có khái niệm HA nhưng dùng quorum voting — các pgpool nodes vote cho nhau. Đây là mechanism khác về bản chất:

Patronipgpool Quorum
MechanismRaft consensus qua etcdMajority voting giữa pgpool nodes
Consensus storeetcd (external)Built-in giữa pgpool nodes
What it decidesAi là PostgreSQL primaryPgpool node nào active
ScopeDatabase-level HAProxy-level HA

Patroni giải quyết vấn đề ở tầng database; pgpool quorum giải quyết vấn đề ở tầng proxy. Chúng không thay thế nhau.

etcd dependency

etcd phải highly available riêng. Single-node etcd (như trong lab setup) là SPOF — nếu etcd down, Patroni không thể reach consensus và sẽ demote primary xuống read-only để tránh split-brain. Production setup cần etcd cluster 3 hoặc 5 nodes.

REST API

Patroni expose HTTP REST API (mặc định port 8008) cho health check và management:

  • GET / — cluster status (primary trả 200, replica trả 503 → dùng được làm health check cho load balancer)
  • POST /failover — manual failover
  • patronictl CLI wrap API này

Connections

Sources