Dưới đây là hướng dẫn đầy đủ cách cấu hình Master-Slave (Streaming Replication) trong PostgreSQL 12 trên hệ điều hành Linux (Ubuntu/CentOS đều được), giúp đồng bộ dữ liệu từ server Master (Primary) sang Slave (Replica) theo thời gian thực.
hot_standby
.ntp
hoặc chrony
).Ví dụ:
192.168.1.10
192.168.1.11
File: postgresql.conf
sudo nano /etc/postgresql/12/main/postgresql.conf
Tìm và sửa/giá trị:
listen_addresses = '*' # Cho phép tất cả IP kết nối
wal_level = replica # Cho phép ghi WAL cho replication
max_wal_senders = 5 # Số lượng kết nối slave tối đa
wal_keep_segments = 64 # Dữ liệu WAL giữ lại (hoặc wal_keep_size = 512MB với bản 12+)
hot_standby = on # Cho phép replica đọc
File: pg_hba.conf
sudo nano /etc/postgresql/12/main/pg_hba.conf
Thêm dòng sau:
host replication replicator 192.168.1.11/32 md5
replicator
là user replication (sẽ tạo ở bước sau).
sudo -u postgres psql
Trong psql:
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '123456';
q
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/12/main/*
pg_basebackup
để copy dữ liệu từ Mastersudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/postgresql/12/main -U replicator -P -v --wal-method=stream
Nhập mật khẩu
123456
nếu được yêu cầu.
standby.signal
sudo -u postgres touch /var/lib/postgresql/12/main/standby.signal
Trong PostgreSQL 12+, không dùng
recovery.conf
nữa, thay bằng filestandby.signal
và cấu hình trongpostgresql.conf
.
postgresql.conf
trên Slavesudo nano /etc/postgresql/12/main/postgresql.conf
Thêm hoặc sửa:
hot_standby = on
primary_conninfo = 'host=192.168.1.10 port=5432 user=replicator password=123456'
sudo systemctl start postgresql
SELECT * FROM pg_stat_replication;
Bạn sẽ thấy thông tin kết nối của replicator
.
ps aux | grep wal
Hoặc kiểm tra log: /var/log/postgresql/postgresql-12-main.log
replicator
phức tạp và giới hạn IP trong pg_hba.conf
.repmgr
, Patroni
để tự động failover, high availability.SELECT pid, usename, client_addr, state, sync_state
FROM pg_stat_replication;
client_addr
: IP máy Slave.state
: streamingsync_state
: async / sync / potentialBạn có thể kiểm tra file log:
sudo tail -f /var/log/postgresql/postgresql-12-main.log
Nếu kết nối đúng, bạn sẽ thấy log kiểu:
started streaming WAL from primary
Trên Master:
CREATE TABLE test_replica(id INT PRIMARY KEY, name TEXT);
INSERT INTO test_replica VALUES (1, 'Hello replica!');
Trên Slave:
sudo -u postgres psql
SELECT * FROM test_replica;
Nếu thấy dữ liệu giống y hệt ⇒ replication hoạt động tốt.
PostgreSQL sẽ tự động nhận ra file standby.signal
khi khởi động lại, không cần recovery.conf
.
Nhưng bạn nên đảm bảo primary_conninfo
vẫn tồn tại trong postgresql.conf
.
Kiểm tra:
grep primary_conninfo /etc/postgresql/12/main/postgresql.conf
Mặc định, replication là asynchronous → dữ liệu trên Slave có thể trễ.
Nếu muốn đồng bộ tuyệt đối (dữ liệu ghi xong trên Slave thì mới commit trên Master), hãy bật synchronous mode:
postgresql.conf
synchronous_commit = on
synchronous_standby_names = '*'
Hoặc chỉ định Slave cụ thể:
'standby01'
postgresql.conf
primary_conninfo = 'application_name=standby01 host=192.168.1.10 port=5432 user=replicator password=123456'
Khi Master bị tắt hoặc gặp sự cố:
sudo systemctl stop postgresql
sudo rm /var/lib/postgresql/12/main/standby.signal
Mở postgresql.conf
, xóa hoặc comment dòng primary_conninfo
.
Sau đó:
sudo systemctl start postgresql
→ Lúc này, Slave sẽ hoạt động như một Master.
📌 Lưu ý: để tránh split-brain, bạn phải đảm bảo Master cũ không hoạt động nữa!
Bạn có thể thêm nhiều Slave bằng cách lặp lại các bước:
pg_basebackup
standby.signal
primary_conninfo
theo user replicationpg_hba.conf
trên Masterrsyslog
để theo dõi log replication riêng.log_line_prefix
để ghi log truy vấn theo IP người dùng.Ví dụ trong postgresql.conf
:
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
Nếu bạn cần mình viết script tự động hóa toàn bộ cấu hình Master-Slave, hoặc hỗ trợ triển khai bằng Docker, Ansible hay systemd service kiểm tra, mình có thể hỗ trợ tiếp nhé.
thêm
Tuyệt vời, mình sẽ tiếp tục bổ sung các nội dung nâng cao hơn để bạn có thể triển khai hệ thống PostgreSQL Master-Slave một cách chuyên nghiệp và ổn định.
Trên Master, bạn có thể dùng:
SELECT
application_name,
client_addr,
state,
write_lag,
flush_lag,
replay_lag
FROM pg_stat_replication;
Hoặc đo thủ công:
SELECT
now() - pg_last_xact_replay_timestamp() AS replication_delay;
Chạy trên Slave để biết slave đang bị trễ bao nhiêu so với master.
Thay vào đó, bạn có thể:
pg_basebackup
từ Slave nếu đảm bảo sync đầy đủ.pgBackRest
, Barman
, hoặc wal-g
– các công cụ hỗ trợ backup trên hệ thống replication chuẩn hơn.Replication Slot đảm bảo rằng Master không xóa WAL file trước khi Slave bắt kịp.
Trên Master, tạo slot:
SELECT * FROM pg_create_physical_replication_slot('slot1');
Sau đó, chỉnh trên Slave:
postgresql.conf:
primary_slot_name = 'slot1'
Ưu điểm:
📌 Lưu ý: slot này cần được theo dõi vì nếu Slave chết lâu → WAL sẽ phình to (vì bị giữ lại).
Bạn có thể cấu hình nhiều Slave giống nhau:
SELECT * FROM pg_create_physical_replication_slot('slot2');
SELECT * FROM pg_create_physical_replication_slot('slot3');
primary_slot_name = 'slot2' -- hoặc 'slot3'
application_name
riêng biệt trong primary_conninfo
.standby.signal
riêng biệt.main/
riêng biệt nếu cùng máy.Trên Master và Slave, mở postgresql.conf
:
shared_preload_libraries = 'pg_stat_statements'
Sau đó chạy:
CREATE EXTENSION pg_stat_statements;
Truy vấn:
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
→ Giúp bạn xem những truy vấn chậm nhất hoặc nặng nhất.
Bạn có thể cài postgres_exporter trên cả Master và Slave:
→ Hiển thị bằng Grafana giúp giám sát tình trạng replication trực quan.
pg_rewind
để khôi phục Master sau failoverNếu bạn từng failover sang Slave, và sau đó muốn dùng lại Master cũ như một Slave, bạn cần dùng pg_rewind
.
Ví dụ:
sudo -u postgres pg_rewind --target-pgdata=/var/lib/postgresql/12/main --source-server="host=192.168.1.11 user=replicator dbname=postgres"
→ Khôi phục dữ liệu nhanh mà không cần pg_basebackup
lại từ đầu.
pg_wal/
).archive_mode
để sao lưu WAL ra ổ đĩa phụ:archive_mode = on
archive_command = 'cp %p /mnt/wal_archive/%f'
+------------------+ +------------------+
| PostgreSQL | streaming over TCP | PostgreSQL |
| Master |<--------------------->| Slave |
| 192.168.1.10 | (replicator) | 192.168.1.11 |
+------------------+ +------------------+
|
|--- optional backup/monitor tools (pgBackRest, Prometheus, ...)
archive_mode
+ restore_command
cho WAL logKhi sử dụng streaming replication, nếu Slave ngắt kết nối lâu, thì các WAL file có thể bị xóa trước khi nó kịp đồng bộ → gây lỗi.
Giải pháp: kết hợp streaming replication + WAL archive backup.
postgresql.conf:
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'
%p
: đường dẫn WAL file.%f
: tên file.postgresql.conf:
restore_command = 'cp /var/lib/postgresql/wal_archive/%f %p'
→ Nếu replication stream bị ngắt, Slave sẽ lấy WAL từ thư mục archive để bắt kịp.
Mặc định replication sử dụng kết nối TCP không mã hóa. Trong môi trường cloud hoặc production nên bật SSL:
postgresql.conf:
ssl = on
ssl_cert_file = '/etc/ssl/certs/server.crt'
ssl_key_file = '/etc/ssl/private/server.key'
Cấp quyền trong pg_hba.conf
:
hostssl replication replicator 192.168.1.11/32 md5
Thêm sslmode=require
vào primary_conninfo
:
primary_conninfo = 'host=192.168.1.10 port=5432 user=replicator password=123456 sslmode=require'
auto.conf
để tránh bị mất cấu hình khi pg_basebackup
File postgresql.auto.conf
tự động ghi cấu hình, nếu bạn chỉnh qua ALTER SYSTEM
.
Để đảm bảo primary_conninfo
và primary_slot_name
không bị ghi đè:
echo "primary_conninfo = 'host=192.168.1.10 user=replicator password=123456'" >> /var/lib/postgresql/12/main/postgresql.auto.conf
echo "primary_slot_name = 'slot1'" >> /var/lib/postgresql/12/main/postgresql.auto.conf
WAL segment (write-ahead log) mặc định có thể chiếm nhiều dung lượng.
Bạn có thể giảm:
wal_keep_size = 256MB
max_wal_size = 1GB
min_wal_size = 80MB
Và kết hợp với archive để tránh mất dữ liệu.
🛠 Lỗi | 💡 Cách xử lý |
---|---|
FATAL: password authentication failed for user "replicator" | Kiểm tra pg_hba.conf + đúng IP + mật khẩu. |
FATAL: could not connect to the primary server | Kiểm tra IP, firewall, port 5432 mở chưa. |
WAL segment removed while still needed | Bật archive_mode + wal_keep_segments lớn hơn. |
standby.signal exists but no primary_conninfo | Xem lại postgresql.conf , cần có primary_conninfo . |
ERROR: requested WAL segment has already been removed | Dùng archive hoặc cấu hình replication slot . |
Công cụ | Mô tả |
---|---|
Patroni | Cluster HA sử dụng etcd , tự động failover. |
repmgr | Dễ triển khai, hỗ trợ failover thủ công và tự động. |
Pgpool-II | Load balancing giữa master/slave + failover detection. |
Keepalived + Virtual IP | Tạo IP ảo chung cho master/slave, giúp client kết nối ổn định khi failover. |
Nếu bạn dùng PHP, Node.js, Python..., nên thiết lập ứng dụng như sau:
Bạn có thể cấu hình trong ORM hoặc code routing logic như sau:
if (query_type == 'SELECT') {
connect_to('slave');
} else {
connect_to('master');
}
Hoặc dùng thư viện hỗ trợ như read-write split
.
Trường hợp Slave lỗi quá nặng, tốt nhất bạn nên:
# Stop PostgreSQL
sudo systemctl stop postgresql
# Remove old data
sudo rm -rf /var/lib/postgresql/12/main/*
# Sync lại bằng pg_basebackup
sudo -u postgres pg_basebackup -h master_ip -D /var/lib/postgresql/12/main -U replicator -P -v --wal-method=stream
# Tạo lại standby.signal
sudo touch /var/lib/postgresql/12/main/standby.signal
# Start lại
sudo systemctl start postgresql
Bạn muốn mình tạo 1 shell script như sau?
setup_pg_master.sh
setup_pg_slave.sh
Tự động hóa:
postgresql.conf
, pg_hba.conf
replicator
userstandby.signal
primary_conninfo