Bài viết

HA #1: Cài đặt PostgreSQL Master-Slave Replication

Hướng dẫn thực chiến cài PostgreSQL Master-Slave replication trên Linux, cấu hình WAL streaming và quy trình promote slave khi master gặp sự cố.

HA #1: Cài đặt PostgreSQL Master-Slave Replication

Hệ thống database chạy trên một node duy nhất là một quả bom hẹn giờ. Không phải nếu nó chết — mà là khi nào. Bài này ghi lại cách cài đặt mô hình Master-Slave để đọc được phân tải và có sẵn một bản dự phòng khi node chính gặp sự cố.

Bối cảnh

Mô hình này phù hợp khi bạn:

  • Có lượng read query nhiều hơn write đáng kể
  • Muốn có node dự phòng sẵn sàng promote lên Master khi cần
  • Chạy trên 2 server riêng biệt (không phải Docker Compose trên cùng host)

Môi trường bài này:

  Master Slave
IP 192.168.1.10 192.168.1.11
OS Ubuntu 22.04 Ubuntu 22.04
PostgreSQL 15 15
Port 5432 5432

Phiên bản PostgreSQL trên Master và Slave phải khớp nhau — ít nhất là cùng major version.


Cài đặt PostgreSQL trên cả 2 node

Chạy trên cả Master và Slave:

1
2
3
4
sudo apt update
sudo apt install -y postgresql-15
sudo systemctl enable postgresql
sudo systemctl start postgresql

Kiểm tra version:

1
2
psql --version
# postgresql 15.x

Cấu hình Master

1. Tạo replication user

1
sudo -u postgres psql
1
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_password_here';

2. Chỉnh postgresql.conf

1
sudo nano /etc/postgresql/15/main/postgresql.conf

Tìm và sửa các dòng sau:

1
2
3
4
listen_addresses = '*'
wal_level = replica
max_wal_senders = 3
wal_keep_size = 64

Giải thích:

  • wal_level = replica — bật WAL ở mức đủ cho streaming replication
  • max_wal_senders — số kết nối streaming tối đa cho phép (mỗi Slave cần 1)
  • wal_keep_size — giữ lại WAL segments để Slave có thể catch up nếu lag

3. Chỉnh pg_hba.conf

1
sudo nano /etc/postgresql/15/main/pg_hba.conf

Thêm dòng này vào cuối file (thay IP của Slave):

1
host    replication     replicator      192.168.1.11/32     scram-sha-256

4. Restart PostgreSQL

1
sudo systemctl restart postgresql

Cấu hình Slave

1. Dừng PostgreSQL và xóa data directory

1
2
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/15/main/*

Đây là bước quan trọng — Slave phải bắt đầu từ một bản sao chính xác của Master, không phải data cũ.

2. Chạy pg_basebackup

1
2
3
4
5
6
7
sudo -u postgres pg_basebackup \
  -h 192.168.1.10 \
  -U replicator \
  -D /var/lib/postgresql/15/main \
  -P \
  -Xs \
  -R

Flag quan trọng:

  • -Xs — streaming mode, chuyển WAL real-time trong quá trình backup
  • -R — tự động tạo standby.signal và ghi primary_conninfo vào postgresql.auto.conf
  • -P — hiển thị tiến trình

Nhập password khi được hỏi. Quá trình này có thể mất vài phút tùy dung lượng database.

3. Kiểm tra file postgresql.auto.conf

1
sudo cat /var/lib/postgresql/15/main/postgresql.auto.conf

Phải có dòng tương tự:

1
primary_conninfo = 'host=192.168.1.10 port=5432 user=replicator password=strong_password_here'

4. Khởi động Slave

1
sudo systemctl start postgresql

Xác minh replication hoạt động

Trên Master

1
2
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn
FROM pg_stat_replication;

Nếu replication đang chạy, bạn sẽ thấy một row với state = streaming và IP của Slave.

Trên Slave

1
2
SELECT status, received_lsn, last_msg_receipt_time
FROM pg_stat_wal_receiver;

Test thực tế

Trên Master, tạo một bảng test:

1
2
CREATE TABLE replication_test (id serial, note text, ts timestamptz default now());
INSERT INTO replication_test (note) VALUES ('hello from master');

Trên Slave, kiểm tra ngay:

1
2
SELECT * FROM replication_test;
-- Phải thấy row vừa insert

Thử ghi trực tiếp lên Slave (phải bị từ chối):

1
2
INSERT INTO replication_test (note) VALUES ('should fail');
-- ERROR:  cannot execute INSERT in a read-only transaction

Promote Slave thành Master (khi cần)

Khi Master gặp sự cố và bạn cần Slave tiếp quản:

1
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/15/main

Hoặc dùng psql:

1
SELECT pg_promote();

Sau khi promote, Slave sẽ chấp nhận write queries. Lúc này bạn cần cập nhật connection string của application trỏ sang IP mới.

Lưu ý: Nếu Master cũ phục hồi sau đó, không được để nó tự động kết nối lại. Cần rebuild nó thành Slave mới — chạy lại pg_basebackup từ Master mới (node vừa promote).


Những thứ dễ sai

pg_hba.conf sai IP hoặc sai method — Slave kết nối được nhưng bị từ chối auth. Kiểm tra log ở /var/log/postgresql/.

wal_level không đủ — Nếu đang dùng minimal, streaming replication không hoạt động. Phải restart sau khi đổi.

Slave bị lag quá nhiều — Tăng wal_keep_size trên Master. Nếu Slave lag quá threshold thì sẽ mất WAL và phải pg_basebackup lại từ đầu.

Firewall block port 5432 — Kiểm tra ufw hoặc iptables trên cả hai node.


Bước tiếp theo

Mô hình này giải quyết được việc phân tải read và có bản dự phòng. Nhưng application vẫn phải tự quản lý việc kết nối đến đúng node — Master cho write, Slave cho read.

Bài tiếp theo sẽ đặt PgBouncer vào giữa để gom và tái sử dụng connection, tránh tình trạng database bị quá tải kết nối khi traffic tăng.

Bài viết này được cấp phép bởi tác giả theo giấy phép CC BY 4.0 .