Một file dump hằng đêm có thể cứu bạn khỏi lỗi thao tác nhầm, nhưng chưa chắc cứu được toàn bộ hệ thống khi database lớn, downtime kéo dài hoặc cần khôi phục về đúng thời điểm trước khi sự cố xảy ra. Với PostgreSQL, chiến lược backup tốt thường không chọn một công cụ duy nhất, mà kết hợp pg_dump, pg_basebackup, WAL archive và PITR theo mục tiêu RPO/RTO của từng workload.
Bài này đi theo hướng thực tế cho sysadmin/DevOps: khi nào dùng logical backup, khi nào cần physical backup, cách bật WAL archiving, cách thiết kế lịch backup, và checklist restore để backup không chỉ “có file” mà thật sự khôi phục được.
1. Trước khi chọn tool: xác định RPO và RTO
Backup PostgreSQL nên bắt đầu bằng hai câu hỏi vận hành:
- RPO — có thể mất tối đa bao nhiêu dữ liệu? 24 giờ, 1 giờ, 5 phút hay gần như 0?
- RTO — hệ thống được phép downtime bao lâu để restore? 4 giờ, 30 phút hay vài phút?
Nếu RPO là 24 giờ và database nhỏ, pg_dump theo lịch có thể đủ. Nếu cần khôi phục đến thời điểm ngay trước khi developer chạy nhầm DELETE, bạn cần base backup kết hợp WAL archive để PITR. Nếu database vài trăm GB đến vài TB, chỉ dựa vào logical dump thường khiến thời gian backup/restore quá dài.
Nguyên tắc quan trọng: backup strategy không được đánh giá bằng thời gian tạo backup, mà bằng khả năng restore đúng dữ liệu trong thời gian chấp nhận được.
2. pg_dump: logical backup linh hoạt cho database nhỏ và restore chọn lọc
pg_dump tạo logical backup cho một database. Nó đọc schema và dữ liệu rồi xuất ra SQL hoặc archive format. Điểm mạnh là dễ di chuyển giữa server, dễ restore chọn lọc schema/table, phù hợp backup trước khi migration, nâng version hoặc thay đổi cấu trúc dữ liệu.
Với môi trường production, nên ưu tiên custom format -Fc thay vì plain SQL vì có thể dùng pg_restore, restore song song, restore từng object và nén tốt hơn.
# Backup một database ở custom format
pg_dump -h 127.0.0.1 -U app_user -d app_db -Fc \
-f /backup/postgresql/app_db_$(date +%F_%H%M).dump
# Kiểm tra danh sách object trong file backup
pg_restore -l /backup/postgresql/app_db_2026-07-01_0200.dump | head
# Restore vào database mới
createdb -h 127.0.0.1 -U postgres app_db_restore
pg_restore -h 127.0.0.1 -U postgres -d app_db_restore \
--jobs=4 --verbose /backup/postgresql/app_db_2026-07-01_0200.dump
Khi cần dump toàn bộ instance theo dạng logical, có thể dùng pg_dumpall, đặc biệt để lưu roles và tablespaces:
# Backup global objects: roles, tablespaces
pg_dumpall -h 127.0.0.1 -U postgres --globals-only \
> /backup/postgresql/globals_$(date +%F).sql
Hạn chế của pg_dump là restore có thể chậm với database lớn, không thể PITR đến một thời điểm bất kỳ, và mỗi database cần được backup riêng. Vì vậy, với production có yêu cầu RPO thấp, pg_dump nên là một lớp backup bổ sung, không phải lớp duy nhất.
3. pg_basebackup: physical backup cho toàn bộ cluster
pg_basebackup tạo bản sao vật lý của toàn bộ PostgreSQL cluster. Nó phù hợp để làm nền cho PITR, dựng standby server, hoặc restore nhanh hơn logical dump trong nhiều trường hợp. Khác với pg_dump, pg_basebackup không backup từng database riêng lẻ; nó lấy toàn bộ data directory, bao gồm tất cả database trong cluster.
Để chạy pg_basebackup, user kết nối cần quyền REPLICATION hoặc superuser, và pg_hba.conf phải cho phép replication connection.
-- Tạo user backup
CREATE ROLE backup_user WITH LOGIN REPLICATION PASSWORD 'strong-password';
# Ví dụ dòng pg_hba.conf cho backup server
host replication backup_user 10.10.10.20/32 scram-sha-256
Ví dụ tạo base backup dạng tar, nén gzip, kèm WAL cần thiết trong quá trình backup:
export PGPASSWORD='strong-password'
pg_basebackup -h 10.10.10.10 -U backup_user \
-D /backup/postgresql/base/$(date +%F_%H%M) \
-Ft -z -P -X stream
-Ft: xuất dạng tar.-z: nén gzip.-P: hiển thị tiến trình.-X stream: stream WAL trong lúc backup để backup có thể restore nhất quán.
Base backup giúp bạn có “mốc nền” để replay WAL. Nếu không lưu WAL liên tục sau base backup, bạn chỉ restore được về thời điểm backup hoàn tất, không đạt PITR đúng nghĩa.
4. WAL archive và PITR: khôi phục đến đúng thời điểm trước sự cố
PostgreSQL ghi thay đổi vào WAL (Write-Ahead Log) trước khi dữ liệu được flush vào data files. Khi bật continuous archiving, các WAL segment hoàn tất sẽ được copy ra một nơi an toàn. Kết hợp base backup + WAL archive, bạn có thể replay thay đổi và dừng tại một thời điểm cụ thể, ví dụ 10:31:00 ngay trước khi query lỗi chạy lúc 10:32:15.
Cấu hình cơ bản trong postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /mnt/pg_wal_archive/%f && cp %p /mnt/pg_wal_archive/%f'
archive_timeout = 300
Trong production, không nên chỉ copy WAL vào cùng disk với database. Hãy đẩy WAL sang backup server, object storage hoặc hệ thống backup độc lập. Nếu dùng object storage, bạn có thể bọc bằng script riêng:
archive_command = '/usr/local/bin/archive-wal.sh %p %f'
#!/usr/bin/env bash
set -euo pipefail
SRC="$1"
FILE="$2"
DEST="s3://company-backup/postgresql/wal/${FILE}"
aws s3 cp "$SRC" "$DEST" --only-show-errors
archive_command phải trả exit code 0 chỉ khi WAL đã được lưu thành công. Nếu command báo thành công giả, bạn có thể mất WAL mà không biết. Nếu command luôn fail, thư mục pg_wal có thể phình to và làm đầy disk.
5. Ví dụ quy trình PITR trên PostgreSQL phiên bản mới
Giả sử bạn có base backup tại /backup/base/2026-07-01_0200 và WAL archive tại /backup/wal. Mục tiêu là restore về 2026-07-01 10:31:00+07.
# 1. Dừng PostgreSQL trên restore server
systemctl stop postgresql
# 2. Di chuyển data dir cũ nếu có
mv /var/lib/postgresql/16/main /var/lib/postgresql/16/main.bak.$(date +%s)
mkdir -p /var/lib/postgresql/16/main
# 3. Giải nén base backup
cd /var/lib/postgresql/16/main
tar -xzf /backup/base/2026-07-01_0200/base.tar.gz
chown -R postgres:postgres /var/lib/postgresql/16/main
chmod 700 /var/lib/postgresql/16/main
Tạo file recovery.signal và cấu hình restore WAL:
touch /var/lib/postgresql/16/main/recovery.signal
cat >> /var/lib/postgresql/16/main/postgresql.auto.conf <<'EOF'
restore_command = 'cp /backup/wal/%f %p'
recovery_target_time = '2026-07-01 10:31:00+07'
recovery_target_action = 'pause'
EOF
chown postgres:postgres /var/lib/postgresql/16/main/recovery.signal /var/lib/postgresql/16/main/postgresql.auto.conf
Khởi động PostgreSQL và theo dõi log:
systemctl start postgresql
journalctl -u postgresql -f
Khi recovery đã pause tại target, kiểm tra dữ liệu. Nếu đúng, promote để đưa cluster ra khỏi recovery:
sudo -u postgres psql -c "SELECT pg_wal_replay_resume();"
# hoặc nếu cần promote rõ ràng
sudo -u postgres pg_ctlcluster 16 main promote
Luôn restore vào server riêng trước khi thay production. PITR có thể tạo timeline mới; vì vậy cần quản lý timeline history files cùng WAL archive nếu có nhiều lần recovery.
6. Lịch backup khuyến nghị cho production vừa và nhỏ
Một chiến lược cân bằng cho nhiều hệ thống web/app backend có thể như sau:
- Hằng ngày:
pg_dump -Fccho database quan trọng, giữ 7-14 bản gần nhất để restore nhanh từng database/table. - Hằng tuần:
pg_basebackuptoàn cluster, giữ ít nhất 2-4 tuần tùy dung lượng. - Liên tục: bật WAL archive sang storage độc lập để PITR.
- Hằng tháng: restore test tự động vào môi trường staging hoặc restore server.
- Trước thay đổi lớn: tạo logical dump riêng cho database/schema liên quan.
Retention nên dựa trên yêu cầu vận hành và chi phí storage. Ví dụ: logical dump giữ 14 ngày, base backup giữ 4 tuần, WAL giữ đủ để cover toàn bộ base backup còn hiệu lực. Nếu base backup cũ nhất là 4 tuần, WAL cần đủ từ thời điểm base backup đó bắt đầu, nếu không PITR từ bản base đó sẽ không hoàn chỉnh.
7. Checklist an toàn: backup phải được kiểm chứng
Những lỗi backup PostgreSQL thường gặp không nằm ở command tạo backup, mà nằm ở phần vận hành xung quanh:
- Backup nằm cùng server/cùng disk với database production.
- Không kiểm tra exit code và log của job backup.
- Không mã hóa backup chứa dữ liệu nhạy cảm.
- Không test restore định kỳ.
- WAL archive bị thiếu segment nhưng không có cảnh báo.
- Dump thành công nhưng không backup roles, extension hoặc cấu hình cần thiết.
- Không ghi lại version PostgreSQL, OS package và tham số quan trọng khi restore.
Một job backup tối thiểu nên có logging, checksum và cảnh báo:
BACKUP=/backup/postgresql/app_db_$(date +%F_%H%M).dump
LOG=/var/log/postgresql-backup.log
if pg_dump -h 127.0.0.1 -U app_user -d app_db -Fc -f "$BACKUP"; then
sha256sum "$BACKUP" > "${BACKUP}.sha256"
echo "$(date -Is) OK $BACKUP" >> "$LOG"
else
echo "$(date -Is) FAILED pg_dump app_db" >> "$LOG"
# gửi alert qua monitoring/email/chatops tại đây
exit 1
fi
Nếu backup lưu lên object storage, bật versioning/object lock nếu phù hợp để giảm rủi ro ransomware hoặc xóa nhầm. Với dữ liệu nhạy cảm, mã hóa trước khi upload hoặc dùng server-side encryption có quản lý key rõ ràng.
8. Khi nào dùng công cụ chuyên dụng?
Khi hệ thống lớn hơn, bạn nên cân nhắc các công cụ như pgBackRest, Barman hoặc WAL-G. Các công cụ này giúp quản lý full/incremental backup, WAL archiving, retention, compression, encryption, parallelism và restore workflow tốt hơn so với script tự viết.
Tuy vậy, hiểu rõ pg_dump, pg_basebackup, WAL và PITR vẫn rất quan trọng. Công cụ chuyên dụng chỉ tự động hóa quy trình; nó không thay thế việc thiết kế RPO/RTO, kiểm tra restore và giám sát backup.
Kết luận
Với PostgreSQL, chiến lược backup tốt nên có nhiều lớp. pg_dump -Fc phù hợp cho logical backup, restore chọn lọc và thao tác trước migration. pg_basebackup cung cấp physical base backup cho toàn cluster. WAL archive là phần bắt buộc nếu bạn muốn PITR và giảm RPO xuống mức phút hoặc tốt hơn.
Điểm quan trọng nhất: hãy test restore định kỳ. Một backup chưa từng được restore thành công chỉ là một giả định, không phải phương án disaster recovery.
FAQ nhanh
pg_dump có đủ cho production không?
Có thể đủ với database nhỏ, RPO 24 giờ và RTO không quá gắt. Với hệ thống cần PITR hoặc database lớn, nên kết hợp thêm physical backup và WAL archive.
Có cần backup WAL nếu đã chạy pg_basebackup?
Có, nếu bạn muốn PITR sau thời điểm base backup. Base backup là mốc nền; WAL archive chứa các thay đổi để replay đến thời điểm cần khôi phục.
Nên restore test bao lâu một lần?
Tối thiểu hằng tháng cho production. Với hệ thống quan trọng, nên tự động restore test hằng tuần hoặc sau mỗi thay đổi lớn trong backup pipeline.
