Bài 3: Giới thiệu Patroni và etcd

Hiểu rõ Patroni hoạt động thế nào, vai trò của DCS (etcd/Consul/ZooKeeper), thuật toán Raft consensus và cơ chế tự động leader election.

8 min read
Bài 3: Giới thiệu Patroni và etcd

Mục tiêu

Sau bài học này, bạn sẽ hiểu:

  • Patroni là gì và cách hoạt động
  • DCS (Distributed Configuration Store) - etcd/Consul/ZooKeeper
  • Consensus algorithm (Raft)
  • Leader election & Failover mechanism
  • Split-brain problem và cách giải quyết

1. Patroni là gì?

Giới thiệu

Patroni là một template HA (High Availability) mã nguồn mở cho PostgreSQL, được phát triển bởi Zalando. Nó tự động hóa việc quản lý PostgreSQL cluster, bao gồm:

  • Leader election: Tự động chọn primary node
  • Automatic failover: Chuyển đổi dự phòng tự động khi primary bị lỗi
  • Configuration management: Quản lý cấu hình tập trung
  • Health checking: Giám sát sức khỏe của các nodes liên tục

Kiến trúc Patroni

The Patroni architecture is a popular choice for managing PostgreSQL clusters.

Cách hoạt động của Patroni

  1. Khởi động: Mỗi Patroni instance kết nối đến DCS (etcd)
  2. Leader election: Các node cạnh tranh để trở thành leader trong DCS
  3. Role assignment: Node giành được leader lock sẽ promote PostgreSQL thành primary
  4. Health monitoring: Patroni liên tục kiểm tra:
    • PostgreSQL process health
    • Replication status
    • DCS connectivity
  5. Auto failover: Nếu leader bị lỗi, Patroni tự động:
    • Phát hiện sự cố
    • Chọn replica phù hợp nhất
    • Promote replica mới thành primary
    • Cập nhật các replica còn lại

Các thành phần chính

Patroni daemon

  • Chạy trên mỗi PostgreSQL node
  • Quản lý lifecycle của PostgreSQL
  • Thực hiện health checks
  • Tương tác với DCS

REST API

  • Endpoint cho health checks: http://node:8008/health
  • Endpoint cho read-only: http://node:8008/read-only
  • Endpoint cho primary: http://node:8008/master (deprecated) hoặc /primary

patronictl

  • CLI tool để quản lý cluster
  • Commands: list, switchover, failover, reinit, restart, reload

2. DCS - Distributed Configuration Store

Vai trò của DCS

DCS là trung tâm điều phối cho Patroni cluster, lưu trữ:

  • Leader key: Thông tin node nào đang là leader (TTL-based)
  • Configuration: Cấu hình PostgreSQL và Patroni
  • Member information: Danh sách các nodes trong cluster
  • Failover/Switchover state: Trạng thái chuyển đổi

So sánh các DCS phổ biến

Tính năngetcdConsulZooKeeper
Ngôn ngữGoGoJava
ConsensusRaftRaftZAB (Paxos-like)
APIgRPC, HTTPHTTP, DNSCustom protocol
SetupĐơn giảnTrung bìnhPhức tạp
PerformanceCaoCaoTrung bình
Tài liệuTốtRất tốtTrung bình
Sử dụngKubernetes, PatroniService mesh, HAHadoop, Kafka

Khuyến nghị: etcd cho hầu hết các trường hợp vì đơn giản và hiệu năng cao.

etcd - Distributed Key-Value Store

Đặc điểm chính:

  • Strongly consistent (CAP theorem: CP)
  • Distributed và highly available
  • Fast (sub-millisecond latency)
  • Simple API
  • Watch mechanism cho real-time updates

Cấu trúc dữ liệu trong etcd cho Patroni:

/service/postgres/
├── config          # Cấu hình cluster
├── initialize      # Bootstrap token
├── leader          # Leader lock (TTL: 30s)
├── members/
│   ├── node1      # Thông tin node1
│   ├── node2      # Thông tin node2
│   └── node3      # Thông tin node3
├── optime/
│   └── leader     # LSN của leader
└── failover       # Failover/switchover instructions

3. Consensus Algorithm - Raft

Raft là gì?

Raft là thuật toán consensus được thiết kế để dễ hiểu hơn Paxos, đảm bảo:

  • Safety: Không bao giờ trả về kết quả sai
  • Liveness: Luôn có tiến triển (khi majority nodes hoạt động)
  • Consistency: Tất cả nodes nhìn thấy cùng một trạng thái

Các vai trò trong Raft

  1. Leader:
    • Xử lý tất cả client requests
    • Replicate log entries đến followers
    • Duy nhất trong một term
  2. Follower:
    • Passive, chỉ nhận requests từ leader
    • Nếu không nhận heartbeat, trở thành candidate
  3. Candidate:
    • Follower timeout thành candidate
    • Request votes từ các nodes khác
    • Nếu thắng bầu cử → Leader

Quy trình Leader Election

The Leader Election Process is crucial for ensuring the consistency and availability of the distributed system.

Chi tiết bầu cử:

  1. Follower không nhận heartbeat trong election timeout (150-300ms ngẫu nhiên)
  2. Chuyển thành Candidate, tăng term number
  3. Vote cho chính mình
  4. Gửi RequestVote RPC đến tất cả nodes
  5. Nếu nhận được majority votes (n/2 + 1):
    • Trở thành Leader
    • Gửi heartbeat ngay lập tức
  6. Nếu timeout hoặc thua cuộc:
    • Quay lại Follower hoặc bắt đầu election mới

Quorum và Majority

Quorum: Số lượng nodes tối thiểu cần để hệ thống hoạt động

Cluster size | Quorum | Tolerated failures
-------------|--------|-------------------
     1       |   1    |        0
     3       |   2    |        1
     5       |   3    |        2
     7       |   4    |        3

Công thức: Quorum = floor(n/2) + 1

Ví dụ với 3 nodes:

  • ✅ 3 nodes active: Cluster healthy
  • ✅ 2 nodes active: Cluster works (quorum met)
  • ❌ 1 node active: Cluster stops (no quorum)

Khuyến nghị: Luôn dùng số lẻ nodes (3, 5, 7) để tối ưu fault tolerance.

4. Leader Election trong Patroni

Cơ chế Leader Lock

Patroni sử dụng DCS để implement distributed lock:

Leader Lock Properties:

Key: /service/postgres/leader
Value: 
  {
    "version": "3.0.2",
    "conn_url": "postgres://node1:5432/postgres",
    "api_url": "http://node1:8008/patroni",
    "xlog_location": 123456789,
    "timeline": 2
  }
TTL: 30 seconds

Quy trình Leader Election

Bước 1: Race Condition

Time: T0 - Leader crashes
Node1: Check DCS → No leader key exists
Node2: Check DCS → No leader key exists  
Node3: Check DCS → No leader key exists

Bước 2: Acquire Lock Attempt

Time: T0 + 100ms
Node1: Try acquire lock → SUCCESS (first to write)
Node2: Try acquire lock → FAILED (key exists)
Node3: Try acquire lock → FAILED (key exists)

Bước 3: Role Assignment

Node1: Promote PostgreSQL to Primary
Node2: Configure as Replica, point to Node1
Node3: Configure as Replica, point to Node1

Bước 4: Maintenance

Every 10 seconds:
Node1 (Leader): 
  - Renew lock (TTL extension)
  - Update xlog_location
  - Send heartbeat

Node2/3 (Followers):
  - Monitor leader key
  - Check replication lag
  - Ready to take over

Tiêu chí chọn Best Replica

Khi failover, Patroni chọn replica dựa trên:

  1. Replication state:
    • streaming > in archive recovery
  2. Timeline: Timeline cao hơn được ưu tiên
  3. XLog position:
    • Replica có LSN gần primary nhất
    • Ít data loss nhất
  4. No replication lag:
    • pg_stat_replication.replay_lag = 0
  5. Explicit candidate: Set trong configuration

Priority tag:

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

Ví dụ:

Primary fails at LSN: 0/3000000

Replica1: LSN=0/3000000, lag=0s     ← BEST CHOICE
Replica2: LSN=0/2FFFFFF, lag=1s
Replica3: LSN=0/2FFFFFE, lag=2s

→ Patroni promotes Replica1

5. Failover Mechanism

Automatic Failover Process

Timeline chi tiết:

Automatic Failover Process

Các bước failover chi tiết

Step 1: Detect failure

# Patroni health check loop
while True:
    if not check_postgresql_health():
        log.error("PostgreSQL unhealthy")
        stop_renewing_leader_lock()
    
    if not check_dcs_connectivity():
        log.error("Lost connection to DCS")
        demote_if_leader()
    
    sleep(10)

Step 2: Leader lock expires

# In etcd
$ etcdctl get /service/postgres/leader
# After TTL: Key not found

# Patroni logs on former leader
WARN: Could not renew leader lock
INFO: Demoting PostgreSQL to standby

Step 3: Replica promotion

# Patroni on promoted replica
INFO: No leader found
INFO: Attempting to acquire leader lock
INFO: Lock acquired successfully
INFO: Promoting PostgreSQL instance
INFO: Updating configuration
INFO: Notifying other members

Step 4: Reconfiguration

-- On promoted replica
SELECT pg_promote();

-- Changes primary_conninfo to null
-- Restarts as read-write

Step 5: Followers repoint

# Other replicas
INFO: New leader detected: node2
INFO: Updating primary_conninfo
INFO: Restarting replication

Monitoring Failover

Các metrics quan trọng:

  • patroni_primary_timeline: Phát hiện timeline changes
  • patroni_xlog_location: Theo dõi WAL position
  • patroni_replication_lag: Lag trước failover
  • patroni_failover_count: Đếm số lần failover

6. Split-Brain Problem

Split-Brain là gì?

Định nghĩa: Tình huống có ≥2 nodes nghĩ mình là Primary, ghi dữ liệu khác nhau → Data divergence.

Nguyên nhân

Network Partition
  1. Network Partition
  2. DCS partition: etcd cluster split
  3. Slow network: Heartbeat timeout nhưng node vẫn sống

Hậu quả của Split-Brain

Hậu quả của Split-Brain

Patroni's Split-Brain Prevention

Cơ chế 1: DCS-based Lock (Primary)

def maintain_leader_lock():
    while is_leader:
        # Must renew within TTL
        success = dcs.renew_lock(ttl=30)
        
        if not success:
            log.critical("Lost leader lock!")
            # Immediate demotion
            demote_to_standby()
            stop_accepting_writes()
            break
        
        sleep(10)

Cơ chế 2: Leader Key Verification

def before_handle_write():
    leader_key = dcs.get("/service/postgres/leader")
    
    if leader_key.owner != my_node_name:
        # I'm not the real leader!
        raise Exception("Not leader anymore")
        demote_immediately()

Cơ chế 3: Timeline Divergence Detection

-- PostgreSQL timeline
SELECT timeline_id FROM pg_control_checkpoint();

-- If timelines diverge:
-- Node1: timeline=5
-- Node2: timeline=6
-- → Data inconsistency detected
-- → Requires pg_rewind or rebuild

Quorum requirement

etcd với 3 nodes:

Scenario 1: Network partition 1-2 split
  Partition A: Node1 (1 node)
    - Cannot get quorum (1 < 2)
    - Cannot write to etcd
    - Demotes to standby ✓
  
  Partition B: Node2, Node3 (2 nodes)
    - Has quorum (2 ≥ 2)
    - Can elect leader
    - Node2 becomes primary ✓
  
Result: Only 1 primary exists ✓

Scenario 2: Complete isolation

Node1: Isolated, loses DCS
  - Tries to renew lock → FAIL
  - Demotes PostgreSQL immediately
  - Stops accepting connections
  
Node2/3: See Node1 gone
  - Elect new leader
  - Only 1 primary in cluster ✓

Watchdog Timer (Advanced Protection)

Hardware watchdog:

# patroni.yml
watchdog:
  mode: required  # or automatic, off
  device: /dev/watchdog
  safety_margin: 5

Hoạt động:

  1. Patroni kicks watchdog device every 10s
  2. If Patroni hangs or loses DCS → stops kicking
  3. After timeout → Watchdog reboots entire node
  4. Prevents "zombie primary" scenario

Best Practices để tránh Split-Brain

  1. Deploy DCS riêng biệt: etcd cluster ở các AZ khác nhau
  2. Monitor DCS health: Alert khi etcd không khỏe
  3. Network redundancy: Nhiều đường network giữa nodes
  4. Proper timeouts:
patroni:
  ttl: 30              # Leader lock TTL
  loop_wait: 10        # Check interval
  retry_timeout: 10    # DCS operation timeout
  1. Enable watchdog: Hardware protection layer
  2. Monitoring:
# Check for timeline divergence
patronictl list

# Expected: All nodes same timeline
+ Cluster: postgres (7001234567890123456) ----+----+-----------+
| Member | Host         | Role    | State   | TL | Lag in MB |
+--------+--------------+---------+---------+----+-----------+
| node1  | 10.0.1.1:5432| Leader  | running | 5  |           |
| node2  | 10.0.1.2:5432| Replica | running | 5  |         0 |
| node3  | 10.0.1.3:5432| Replica | running | 5  |         0 |
+--------+--------------+---------+---------+----+-----------+

Recovery từ Split-Brain

Nếu xảy ra split-brain:

Step 1: Identify

# Check timeline
patronictl list
# node1: timeline=5
# node2: timeline=6  ← DIVERGED!

Step 2: Choose primary

  • Chọn node có data quan trọng hơn
  • Hoặc node có timeline cao hơn

Step 3: Rebuild diverged replica

# Option 1: pg_rewind (if safe)
patronictl reinit postgres node2

# Option 2: Full rebuild
patronictl remove postgres node2
# Then: reinitialize from scratch

Step 4: Verify

patronictl list
# All nodes same timeline ✓

7. Tổng kết

Key Takeaways

✅ Patroni: Template HA tự động hóa quản lý PostgreSQL cluster

✅ DCS (etcd): Distributed coordination, store configuration và leader lock

✅ Raft consensus: Đảm bảo consistency và leader election trong etcd

✅ Leader election: Automatic, fast (~30-40s), based on TTL locks

✅ Failover: Tự động promote replica tốt nhất khi primary fails

✅ Split-brain prevention: DCS quorum + TTL locks + watchdog

Kiến trúc tổng hợp

Kiến trúc tổng hợp

Câu hỏi ôn tập

  1. Patroni khác gì với Streaming Replication thuần?
  2. Tại sao cần DCS? Không thể dùng database để lưu state được không?
  3. Quorum trong cluster 5 nodes là bao nhiêu?
  4. Patroni chọn replica nào để promote khi failover?
  5. Split-brain xảy ra như thế nào và Patroni ngăn chặn ra sao?
  6. Timeline trong PostgreSQL có ý nghĩa gì?
  7. TTL 30 seconds nghĩa là gì? Tại sao không set TTL = 5 seconds?

Chuẩn bị cho bài tiếp theo

Bài 4 sẽ hướng dẫn chuẩn bị hạ tầng:

  • Setup 3 VMs/Servers
  • Cấu hình network, firewall
  • SSH keys, time sync
  • Dependencies cần thiết
patroni etcd dcs consensus raft leader-election split-brain

Đánh dấu hoàn thành (Bài 3: Giới thiệu Patroni và etcd)