Hướng Dẫn Cấu Hình Cluster PostgreSQL Tự Động Failover Với Patroni Và Etcd Trên VPS
Khái niệm về Tính Sẵn Sàng Cao (High Availability) cho PostgreSQL
Trong kỷ nguyên số, dữ liệu được coi là tài sản vô giá của mọi doanh nghiệp. Việc hệ thống cơ sở dữ liệu gặp sự cố ngừng hoạt động (downtime), dù chỉ trong vài phút, cũng có thể dẫn đến tổn thất lớn về doanh thu, uy tín và trải nghiệm người dùng. Đối với hệ quản trị cơ sở dữ liệu mạnh mẽ như PostgreSQL, việc triển khai một giải pháp có tính sẵn sàng cao (High Availability - HA) là yêu cầu bắt buộc đối với các hệ thống sản xuất (production).
Một hệ thống HA lý tưởng không chỉ dừng lại ở việc sao chép dữ liệu (Replication) từ máy chủ chính (Primary/Master) sang các máy chủ dự phòng (Standby/Replica). Điểm mấu chốt nằm ở khả năng tự động chuyển vùng khi gặp sự cố (Automated Failover). Khi máy chủ Primary bị sập, hệ thống phải tự động phát hiện, đánh giá tình trạng và chỉ định một máy chủ Replica phù hợp lên làm Primary mới mà không cần đến sự can thiệp thủ công của quản trị viên. Để đạt được mục tiêu này một cách an toàn và tin cậy, sự kết hợp giữa Patroni và Etcd là giải pháp hàng đầu hiện nay.
Vai trò của Patroni và Etcd trong kiến trúc Cluster
Để hiểu tại sao Patroni và Etcd lại trở thành bộ đôi hoàn hảo cho PostgreSQL HA, chúng ta cần phân tích sâu vào vai trò cốt lõi của từng thành phần trong mô hình kiến trúc này:
- Etcd (Distributed Consensus Store): Là một kho lưu trữ dữ liệu dạng key-value phân tán, có độ tin cậy cao, thường được sử dụng để lưu trữ cấu hình và quản lý trạng thái của hệ thống cluster. Etcd sử dụng thuật toán đồng thuận Raft để đảm bảo tính nhất quán dữ liệu tuyệt đối giữa các node. Trong kiến trúc Patroni, Etcd đóng vai trò là DCS (Distributed Configuration Store), nơi ghi nhận node nào đang giữ Leader key (quyền Primary) và lưu trữ trạng thái động của toàn bộ cluster.
- Patroni (PostgreSQL HA Template): Là một công cụ quản lý cluster mã nguồn mở được viết bằng Python. Patroni hoạt động như một lớp điều khiển (controller) bọc quanh tiến trình PostgreSQL. Nó liên tục giám sát trạng thái của PostgreSQL cục bộ, tương tác với DCS (Etcd) để thực hiện bầu chọn Leader, tự động cấu hình replication, và thực hiện failover một cách an toàn khi phát hiện Leader gặp sự cố.
Mô hình phối hợp diễn ra như sau: Patroni trên node Primary sẽ liên tục gia hạn một khóa (lease) trên Etcd với một khoảng thời gian TTL (Time-To-Live) nhất định. Nếu node Primary bị sập, Patroni trên node đó không thể gia hạn khóa. Khi khóa hết hạn, các node Patroni Standby sẽ phát hiện ra sự vắng mặt của Leader và lập tức khởi xướng một cuộc bầu chọn trên Etcd. Node Replica nào đồng bộ dữ liệu tốt nhất và giành được khóa trên Etcd sẽ được Patroni nâng cấp lên thành Primary mới.
Chuẩn bị hạ tầng VPS và môi trường hệ thống
Để xây dựng một Cluster PostgreSQL tiêu chuẩn chống lại hiện tượng split-brain (hiện tượng phân rã não bộ dẫn đến xung đột dữ liệu), chúng ta cần một số lượng node lẻ để đảm bảo cơ chế bỏ phiếu bầu chọn của Etcd hoạt động chính xác. Trong bài viết này, chúng tôi hướng dẫn cấu hình trên hệ thống gồm 03 node VPS chạy hệ điều hành Ubuntu Server 22.04 LTS với thông tin quy hoạch IP như sau:
- Node 1 (Primary dự kiến): IP
192.168.10.11- Hostname:db-node1 - Node 2 (Replica dự kiến): IP
192.168.10.12- Hostname:db-node2 - Node 3 (Replica dự kiến): IP
192.168.10.13- Hostname:db-node3
Lưu ý trước khi cài đặt: Đảm bảo các node VPS có thể giao tiếp với nhau qua mạng nội bộ (Private Network) để tối ưu hóa bảo mật và tốc độ truyền tải. Hãy cấu hình tệp tin /etc/hosts trên cả 3 máy chủ để phân giải chính xác hostname của các node.
Các bước cài đặt và cấu hình chi tiết
Bước 1: Cài đặt và cấu hình Etcd Cluster
Etcd cần được cài đặt và thiết lập thành một cluster phân tán trên cả 3 node. Thực hiện lệnh sau trên tất cả các máy chủ:
sudo apt-get update && sudo apt-get install -y etcd-server etcd-clientSau khi cài đặt, tiến hành chỉnh sửa tệp cấu hình cấu hình Etcd tại đường dẫn /etc/default/etcd. Dưới đây là ví dụ cấu hình mẫu cho Node 1 (thực hiện tương tự và thay đổi IP tương ứng cho Node 2 và Node 3):
ETCD_NAME="db-node1"
ETCD_DATA_DIR="/var/lib/etcd/db-node1.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.10.11:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.10.11:2379,http://127.0.0.1:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.10.11:2380"
ETCD_INITIAL_CLUSTER="db-node1=http://192.168.10.11:2380,db-node2=http://192.168.10.12:2380,db-node3=http://192.168.10.13:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-pg-cluster-token"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.10.11:2379"Sau khi cấu hình xong trên cả 3 node, khởi động lại dịch vụ Etcd để thiết lập cluster:
sudo systemctl restart etcd && sudo systemctl enable etcdKiểm tra trạng thái hoạt động của Etcd cluster bằng lệnh: etcdctl endpoint health hoặc etcdctl member list để đảm bảo cả 3 node đều phản hồi trạng thái healthy.
Bước 2: Cài đặt PostgreSQL và Patroni
Tiếp theo, chúng ta cần cài đặt PostgreSQL và các thư viện Python cần thiết cho Patroni trên cả 3 node. Lưu ý, sau khi cài đặt PostgreSQL, hãy tắt và vô hiệu hóa dịch vụ mặc định của PostgreSQL vì Patroni sẽ trực tiếp quản lý việc khởi động/tắt tiến trình này.
sudo apt-get install -y postgresql-15 postgresql-client-15 python3-pip python3-psycopg2
sudo systemctl stop postgresql
sudo systemctl disable postgresql
sudo pip3 install patroni[etcd3]Bước 3: Cấu hình Patroni trên các node
Tạo thư mục cấu hình cho Patroni và cấp quyền cho user postgres:
sudo mkdir -p /etc/patroni
sudo chown postgres:postgres /etc/patroniĐăng nhập dưới quyền user postgres (sudo su - postgres) và tạo tệp cấu hình /etc/patroni/patroni.yml. Cấu hình chi tiết cho Node 1 như sau:
scope: pg-cluster
namespace: /service
name: db-node1
etcd3:
hosts:
- 192.168.10.11:2379
- 192.168.10.12:2379
- 192.168.10.13:2379
restapi:
listen: 192.168.10.11:8008
connect_address: 192.168.10.11:8008
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
shared_buffers: 256MB
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.10.0/24 md5
- host all all 0.0.0.0/0 md5
postgresql:
listen: 192.168.10.11:5432
connect_address: 192.168.10.11:5432
data_dir: /var/lib/postgresql/15/main
bin_dir: /usr/lib/postgresql/15/bin
pgpass: /var/lib/postgresql/.pgpass
authentication:
replication:
username: replicator
password: 'YourSecureReplicationPassword'
superuser:
username: postgres
password: 'YourSecureSuperuserPassword'Chú ý quan trọng: Hãy thay đổi các tham số name, listen, và connect_address sao cho tương ứng với địa chỉ IP của Node 2 và Node 3 khi copy file cấu hình sang các node này.
Khởi chạy hệ thống và kịch bản thử nghiệm Failover
Để quản lý Patroni một cách chuyên nghiệp, hãy tạo một service systemd cho Patroni tại /etc/systemd/system/patroni.service. Sau đó, khởi chạy dịch vụ trên cả 3 node, bắt đầu từ node được chọn làm Primary (Node 1):
sudo systemctl daemon-reload && sudo systemctl start patroni && sudo systemctl enable patroniKhi Patroni được khởi chạy trên Node 1, nó sẽ thấy cấu hình trống trên Etcd và tiến hành chạy lệnh initdb để khởi tạo cơ sở dữ liệu mới. Khi Node 2 và Node 3 khởi chạy, Patroni của chúng sẽ nhận diện được đã có Leader hiện hữu, từ đó tự động thực hiện lệnh pg_basebackup để đồng bộ dữ liệu từ Node 1 về và thiết lập chế độ Streaming Replication một cách hoàn toàn tự động.
Sử dụng công cụ kiểm tra trạng thái cluster của Patroni bằng lệnh:
patronictl -c /etc/patroni/patroni.yml listBạn sẽ thấy một bảng danh sách hiển thị rõ ràng Node 1 đang giữ vai trò Leader với trạng thái running, trong khi Node 2 và Node 3 giữ vai trò Replica.
Thử nghiệm kịch bản tự động chuyển vùng (Failover)
Để chứng minh tính hiệu quả của giải pháp, chúng ta sẽ giả lập một sự cố nghiêm trọng bằng cách tắt đột ngột node Primary (Node 1):
# Trên Node 1, giả lập sập nguồn bằng cách tắt dịch vụ Patroni hoặc tắt hẳn VPS
sudo systemctl stop patroniNgay lập tức, hãy theo dõi log trên Node 2 hoặc Node 3, hoặc chạy lệnh kiểm tra trên các node còn lại. Bạn sẽ quan sát thấy tiến trình sau diễn ra tự động trong vòng vài giây:
- Khóa Leader trên Etcd của Node 1 bị hết hạn do không được gia hạn.
- Patroni trên Node 2 và Node 3 phát hiện Leader đã offline và tiến hành bầu chọn.
- Giả sử Node 2 có vị trí WAL (Write-Ahead Logging) cập nhật nhất, nó sẽ giành được khóa và được Patroni tự động nâng cấp (promote) thành Leader mới.
- Node 3 sẽ tự động nhận diện cấu hình mới và chuyển hướng kết nối replication sang Node 2 làm đích đến.
- Khi Node 1 online trở lại, Patroni sẽ phát hiện cluster đã có Leader mới (Node 2). Nó sẽ tự động hạ cấp Node 1 xuống thành Replica, đồng thời sử dụng tính năng
pg_rewindđể đồng bộ lại dữ liệu bị lệch và kết nối vào hệ thống như một nút dự phòng thông thường mà không gây ra bất kỳ xung đột nào.
Kết luận và các lưu ý vận hành thực tế
Việc triển khai cấu hình Cluster PostgreSQL với Patroni và Etcd trên hạ tầng VPS mang lại một giải pháp High Availability chuẩn doanh nghiệp cực kỳ mạnh mẽ và linh hoạt. Hệ thống có khả năng tự phục hồi, giảm thiểu tối đa thời gian downtime và rủi ro mất mát dữ liệu.
Tuy nhiên, để vận hành hệ thống này một cách tối ưu trong thực tế, các nhà quản trị mạng cần lưu ý một số điểm sau:
- Kết nối Client: Do địa chỉ IP của Primary node có thể thay đổi sau failover, ứng dụng của bạn không nên kết nối trực tiếp đến IP tĩnh của VPS. Hãy sử dụng một lớp Proxy như HAProxy kết hợp với Keepalived hoặc sử dụng tính năng định tuyến của Patroni (như REST API endpoints) để luôn định tuyến chính xác traffic ghi vào node Leader hiện tại.
- Giám sát (Monitoring): Cần thiết lập hệ thống cảnh báo (Prometheus & Grafana) để theo dõi sát sao độ trễ replication (replication lag) và trạng thái của các node trong Etcd cluster.
- Bảo mật: Luôn mã hóa kết nối giữa các node Patroni, Etcd và PostgreSQL bằng chứng chỉ SSL/TLS để đảm bảo an toàn an ninh dữ liệu nội bộ.
