Backup và restore PostgreSQL production bằng pg_dump
Hướng dẫn backup PostgreSQL bằng pg_dump, định dạng custom, pg_restore, lịch cron, kiểm tra restore và lưu bản sao ngoài VPS.
Mục lục bài viết
VPS & Hosting cho dự án của bạn
Khám phá các gói máy chủ và lưu trữ phù hợp từ website cá nhân đến ứng dụng production.
Backup database không hoàn thành khi một file .dump được tạo ra. Một hệ thống backup đáng tin cậy phải trả lời được:
Backup có chạy không?
File có đầy đủ không?
Lưu ở đâu?
Giữ bao lâu?
Ai nhận cảnh báo?
Restore mất bao lâu?
Đã thử restore chưa?
Các phương pháp backup PostgreSQL
Tài liệu PostgreSQL chia ba hướng chính:
- SQL dump.
- File system level backup.
- Continuous archiving và point-in-time recovery.
Bài này tập trung vào pg_dump, phù hợp nhiều dự án vừa và nhỏ.
pg_dump là gì?
pg_dump xuất một database thành script SQL hoặc archive.
Ưu điểm:
- Không cần dừng database.
- Có thể chuyển giữa kiến trúc máy.
- Thường restore được sang PostgreSQL mới hơn.
- Có thể chọn schema/table.
- Dễ dùng.
Hạn chế:
- Restore database lớn có thể lâu.
- Không cung cấp PITR một mình.
- Chỉ dump một database.
- Global roles cần xử lý riêng.
Kiểm tra phiên bản
psql --version
pg_dump --version
Kiểm tra server:
SELECT version();
Nên dùng pg_dump có version tương thích với server.
Các định dạng
Plain SQL
pg_dump database_name > backup.sql
Restore:
psql database_name < backup.sql
Dễ đọc nhưng ít linh hoạt hơn.
Custom format
pg_dump -Fc database_name > backup.dump
Restore bằng pg_restore.
Custom format hỗ trợ lựa chọn object và quy trình restore linh hoạt.
Directory format
pg_dump -Fd -j 4 -f backup_dir database_name
Có thể dump và restore song song.
Backup cơ bản
pg_dump \
-U deployeasy \
-h 127.0.0.1 \
-p 5432 \
-Fc \
-d deployeasy \
-f deployeasy.dump
Tránh đưa password trực tiếp trong command line.
Có thể dùng:
.pgpass.- User backup riêng.
- Secret manager.
- Peer authentication phù hợp.
File .pgpass
~/.pgpass
Format:
hostname:port:database:username:password
Ví dụ:
127.0.0.1:5432:deployeasy:backup_user:SECRET
Permission:
chmod 600 ~/.pgpass
Không commit file này.
User backup
Nguyên tắc:
- User riêng.
- Chỉ cấp quyền cần.
- Password riêng.
- Không dùng superuser nếu không cần.
- Test dump đủ schema và dữ liệu.
Nếu thiếu quyền, dump có thể lỗi hoặc thiếu object.
Script backup
Tạo:
sudo nano /usr/local/bin/backup-deployeasy-postgres
#!/usr/bin/env bash
set -Eeuo pipefail
BACKUP_DIR="/var/backups/deployeasy-postgres"
DATABASE_HOST="127.0.0.1"
DATABASE_PORT="5432"
DATABASE_NAME="deployeasy"
DATABASE_USER="backup_user"
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
OUTPUT="$BACKUP_DIR/${DATABASE_NAME}-${TIMESTAMP}.dump"
TEMP_OUTPUT="${OUTPUT}.tmp"
mkdir -p "$BACKUP_DIR"
pg_dump \
--host="$DATABASE_HOST" \
--port="$DATABASE_PORT" \
--username="$DATABASE_USER" \
--dbname="$DATABASE_NAME" \
--format=custom \
--file="$TEMP_OUTPUT"
mv "$TEMP_OUTPUT" "$OUTPUT"
find "$BACKUP_DIR" \
-type f \
-name "${DATABASE_NAME}-*.dump" \
-mtime +14 \
-delete
echo "Backup created: $OUTPUT"
Permission:
sudo chmod 750 /usr/local/bin/backup-deployeasy-postgres
Dùng file tạm rồi rename giúp tránh coi file dở dang là backup hợp lệ.
Chạy thử
/usr/local/bin/backup-deployeasy-postgres
Kiểm tra:
ls -lh /var/backups/deployeasy-postgres
file /var/backups/deployeasy-postgres/*.dump
Xem nội dung archive
pg_restore --list backup.dump | less
Đây chưa phải bằng chứng restore hoàn chỉnh, nhưng giúp xác nhận archive có mục lục.
Lên lịch cron
crontab -e
Chạy 02:30 mỗi ngày:
30 2 * * * /usr/local/bin/backup-deployeasy-postgres >> /var/log/deployeasy-backup.log 2>&1
Cron có PATH hạn chế; dùng đường dẫn tuyệt đối nếu cần.
Systemd timer là lựa chọn khác với log và trạng thái rõ hơn.
Không lưu duy nhất trên VPS
Nếu VPS bị xóa hoặc ổ đĩa hỏng, backup cùng máy cũng mất.
Mô hình đơn giản:
Database production
Backup local ngắn hạn
Backup object storage hoặc máy khác
Có thể tham khảo nguyên tắc 3-2-1:
3 bản dữ liệu
2 loại phương tiện
1 bản ở vị trí khác
Backup trong Docker Compose
mkdir -p backups
docker compose exec -T database \
pg_dump \
-U deployeasy \
-d deployeasy \
-Fc \
> "backups/deployeasy-$(date +%Y%m%d-%H%M%S).dump"
-T tắt pseudo-TTY, phù hợp với binary archive.
Restore vào database test
Tạo database:
createdb \
-U postgres \
deployeasy_restore_test
Restore:
pg_restore \
-U postgres \
-d deployeasy_restore_test \
--clean \
--if-exists \
backup.dump
--clean drop object trước khi tạo. Chỉ dùng trên database test hoặc khi hiểu tác động.
Restore plain SQL
createdb deployeasy_restore_test
psql deployeasy_restore_test < backup.sql
Restore trong Docker
docker compose exec database \
createdb \
-U deployeasy \
deployeasy_restore_test
docker compose exec -T database \
pg_restore \
-U deployeasy \
-d deployeasy_restore_test \
--clean \
--if-exists \
< backup.dump
Không test trực tiếp vào production.
Kiểm tra restore
Không chỉ nhìn exit code.
Kiểm tra:
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM orders;
So sánh:
- Số bảng.
- Row count quan trọng.
- Index.
- Constraint.
- Function.
- Sequence.
- Permission.
- Smoke test ứng dụng.
Cách tốt là chạy staging bằng database vừa restore.
Roles và global objects
pg_dump không dump toàn bộ global objects như roles.
Dùng:
pg_dumpall --globals-only > globals.sql
File có thể chứa thông tin nhạy cảm. Bảo vệ và review trước khi restore.
Backup toàn cluster
pg_dumpall > cluster.sql
Phù hợp một số hệ thống nhỏ nhưng ít linh hoạt và có thể rất lớn.
Compression
Plain SQL:
pg_dump deployeasy | gzip > deployeasy.sql.gz
Restore:
gunzip -c deployeasy.sql.gz | psql deployeasy_restore_test
Custom format đã có cơ chế compression theo tùy chọn/version; không cần nén hai lần nếu không có lý do.
Mã hóa backup
Nếu backup chứa dữ liệu nhạy cảm:
- Dùng công cụ mã hóa được phê duyệt.
- Lưu khóa tách khỏi backup.
- Có quy trình khôi phục khóa.
- Test decrypt.
- Rotate key.
Backup mã hóa mà mất khóa cũng là mất dữ liệu.
Retention
Ví dụ:
Daily: 14 bản
Weekly: 8 bản
Monthly: 12 bản
Chọn theo:
- Dung lượng.
- Quy định.
- Tốc độ thay đổi.
- RPO.
- Chi phí.
Không chỉ giữ một bản mới nhất vì lỗi logic có thể đã tồn tại trước lúc backup.
RPO và RTO
RPO
Lượng dữ liệu tối đa chấp nhận mất.
Backup mỗi 24 giờ có thể dẫn tới RPO gần 24 giờ.
RTO
Thời gian mục tiêu để khôi phục dịch vụ.
Nếu restore thực tế mất 4 giờ thì không thể chỉ ghi RTO 15 phút mà chưa thay kiến trúc.
Point-in-time recovery
Nếu cần phục hồi tới một thời điểm cụ thể, pg_dump định kỳ chưa đủ. Cần xem:
- WAL archive.
- Base backup.
- Continuous archiving.
- PITR.
- Monitoring archive.
- Restore test.
Managed database có PITR có thể giảm việc vận hành, nhưng vẫn phải hiểu retention và quy trình restore.
Backup trước migration
Trước migration quan trọng:
- Chạy backup.
- Xác minh file.
- Copy offsite.
- Test migration trên bản restore.
- Đo lock và thời gian.
- Chuẩn bị rollback/forward fix.
Backup không làm migration tự động an toàn.
Monitoring backup
Theo dõi:
- Exit code.
- File mới nhất.
- Kích thước bất thường.
- Upload offsite.
- Dung lượng storage.
- Restore test gần nhất.
- Thời gian chạy.
File 0 byte hoặc nhỏ bất thường phải tạo cảnh báo.
Lỗi thường gặp
Version mismatch
Dùng client pg_dump phù hợp hoặc mới hơn theo khả năng hỗ trợ.
Permission denied
Backup user thiếu quyền.
Backup quá nhỏ
Kiểm tra log, database name, schema và pg_restore --list.
Restore thiếu role
Dump global objects hoặc tạo role trước.
Object already exists
Dùng database trống hoặc --clean --if-exists sau khi hiểu tác động.
Hết ổ đĩa
df -h
du -sh /var/backups/*
Không để backup làm đầy production disk.
Checklist
[ ] Xác định RPO và RTO
[ ] Dùng custom format
[ ] User backup riêng
[ ] Password được bảo vệ
[ ] File tạm trước rename
[ ] Retention rõ
[ ] Bản sao ngoài VPS
[ ] Mã hóa khi cần
[ ] Backup global roles
[ ] Monitoring file mới nhất
[ ] Cảnh báo lỗi
[ ] Restore vào DB test
[ ] Smoke test ứng dụng
[ ] Đo thời gian restore
[ ] Backup trước migration
Câu hỏi thường gặp
Copy Docker volume có phải backup không?
Copy file khi PostgreSQL đang chạy có thể không nhất quán. Dùng phương pháp PostgreSQL hỗ trợ.
Backup mỗi ngày có đủ không?
Phụ thuộc RPO. Nếu không thể mất 24 giờ dữ liệu, cần tần suất cao hơn hoặc PITR.
Có cần test restore không?
Có. Restore test là cách chứng minh backup sử dụng được.
Kết luận
Backup đáng tin cậy là quy trình được kiểm tra, không phải chỉ một file. Hãy lưu ngoài VPS, cảnh báo khi lỗi và thực hành restore định kỳ.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
Bảo mật PostgreSQL trên VPS: pg_hba.conf, user và firewall
Hướng dẫn bảo mật PostgreSQL production bằng listen_addresses, pg_hba.conf, role tối thiểu, password, firewall, SSL và SSH tunnel.
Đọc bài →Deploy Node.js production bằng PM2 và Nginx trên VPS
Hướng dẫn deploy ứng dụng Node.js bằng PM2, ecosystem file, biến môi trường, startup, log, Nginx reverse proxy và rollback.
Đọc bài →Domain và DNS là gì? Cách trỏ tên miền về VPS đúng cách
Giải thích domain, DNS, nameserver, bản ghi A, AAAA, CNAME, TXT và quy trình trỏ tên miền về VPS để deploy website.
Đọc bài →