DeployEasy
DatabaseTrung bình

Backup PostgreSQL trên VPS bằng pg_dump và cron: 18 bước có kiểm tra restore

Hướng dẫn backup PostgreSQL tự động trên VPS bằng pg_dump, cron, checksum, retention, lưu ngoài máy chủ và kiểm tra restore định kỳ.

· 17 phút đọc· 3.685 từ
Mục lục bài viết

Quy trình backup PostgreSQL trên VPS bằng pg_dump, cron và kiểm tra restore

Backup PostgreSQL trên VPS không chỉ là chạy pg_dump rồi thấy một file .dump xuất hiện. Một bản backup chỉ thật sự có giá trị khi được tạo đúng lịch, không chứa file lỗi giả thành công, có chính sách lưu giữ, được sao chép ra khỏi VPS và đã từng restore thử.

Bài viết này hướng dẫn quy trình phù hợp với ứng dụng nhỏ và vừa tự quản lý trên Ubuntu: kiểm tra phiên bản PostgreSQL, tạo tài khoản backup, dùng .pgpass, tạo archive dạng custom, chống hai job chạy đồng thời, tạo checksum, dọn bản cũ, chạy bằng cron và restore vào database kiểm thử.

Tóm tắt nhanh: Dùng pg_dump -Fc để tạo logical backup, chỉ đổi tên file tạm sau khi lệnh thành công, kiểm tra archive bằng pg_restore --list, lưu checksum, giữ nhiều phiên bản, sao chép ít nhất một bản ra khỏi VPS và kiểm tra restore định kỳ.

Sơ đồ luồng backup PostgreSQL từ database đến kho lưu trữ ngoài VPS

Demo terminal: tạo và kiểm tra một bản backup

Ví dụ dưới đây tạo archive dạng custom, liệt kê nội dung archive và sinh checksum:

Terminal demo backup PostgreSQL bằng pg_dump và pg_restore

mkdir -p ~/postgres-backup-demo

pg_dump \
  -h 127.0.0.1 \
  -p 5432 \
  -U backup_user \
  -d appdb \
  -Fc \
  -f ~/postgres-backup-demo/appdb.dump

pg_restore --list ~/postgres-backup-demo/appdb.dump > /dev/null
sha256sum ~/postgres-backup-demo/appdb.dump

Lưu ý: Không đưa mật khẩu database trực tiếp vào câu lệnh, shell history, repository hoặc ảnh chụp terminal. Hãy dùng .pgpass, secret manager hoặc cơ chế cấp secret phù hợp với môi trường triển khai.

Phạm vi của bài viết

Quy trình này phù hợp khi:

PostgreSQL chạy trên VPS hoặc trong Docker
Database có kích thước nhỏ đến vừa
Chấp nhận backup theo mốc thời gian
Không yêu cầu Point-in-Time Recovery ở từng phút
Có thể dành tài nguyên để restore thử định kỳ

pg_dump là logical backup của từng database. Với hệ thống có RPO rất thấp, database lớn hoặc cần khôi phục tới một thời điểm chính xác, cần đánh giá thêm physical backup, WAL archiving, streaming replication hoặc dịch vụ database được quản lý.

Mục tiêu sau khi hoàn thành

Có tài khoản hoặc cơ chế kết nối dành cho backup
Mật khẩu không nằm trong script
Backup được tạo bằng file tạm
Job thất bại không để lại file giả thành công
Có checksum và log
Có chính sách retention
Có bản sao ngoài VPS
Có quy trình restore test
Biết RPO và RTO thực tế

Kiến trúc đề xuất

PostgreSQL

    ├── pg_dump -Fc


File tạm trên VPS

    ├── pg_restore --list
    ├── sha256sum
    └── đổi tên thành file hoàn chỉnh


Thư mục backup cục bộ

    ├── retention
    └── sao chép sang máy/kho lưu trữ khác


Restore test định kỳ

Bước 1: Ghi lại thông tin database

Không bắt đầu bằng việc viết cron. Trước tiên, hãy xác định:

Database name:
Host:
Port:
PostgreSQL version:
Kích thước database:
Ứng dụng nào đang dùng:
Thời gian ít tải:
RPO mong muốn:
RTO mong muốn:
Nơi lưu bản sao ngoài VPS:

Kiểm tra phiên bản client:

pg_dump --version
pg_restore --version
psql --version

Kiểm tra server:

psql \
  -h 127.0.0.1 \
  -p 5432 \
  -U postgres \
  -d postgres \
  -c "SHOW server_version;"

Kiểm tra kích thước:

psql \
  -h 127.0.0.1 \
  -U postgres \
  -d appdb \
  -c "SELECT pg_size_pretty(pg_database_size(current_database()));"

Bước 2: Xác định RPO và RTO

RPO là gì?

RPO là lượng dữ liệu tối đa có thể chấp nhận mất.

Ví dụ:

Backup mỗi 24 giờ → có thể mất gần 24 giờ dữ liệu
Backup mỗi 6 giờ  → có thể mất gần 6 giờ dữ liệu
Backup mỗi 1 giờ  → có thể mất gần 1 giờ dữ liệu

Đây là giới hạn theo lịch backup, chưa tính trường hợp job thất bại hoặc bản backup không restore được.

RTO là gì?

RTO là thời gian mục tiêu để dịch vụ hoạt động trở lại.

RTO phụ thuộc vào:

  • Thời gian tải bản backup.
  • Thời gian tạo server mới.
  • Thời gian cài PostgreSQL.
  • Thời gian restore.
  • Thời gian cập nhật secret và DNS.
  • Thời gian kiểm tra ứng dụng.

Không thể biết RTO thật nếu chưa từng diễn tập restore.

Bước 3: Chọn định dạng backup

Plain SQL

pg_dump -d appdb > appdb.sql

Ưu điểm:

  • Có thể đọc bằng text editor.
  • Restore bằng psql.
  • Dễ chỉnh sửa thủ công trong trường hợp đặc biệt.

Nhược điểm:

  • Khó chọn từng object khi restore.
  • Không dùng pg_restore.
  • Thường kém linh hoạt hơn archive.

Custom archive

pg_dump -Fc -d appdb -f appdb.dump

Ưu điểm:

  • Dùng được với pg_restore.
  • Có nén mặc định.
  • Có thể xem danh sách object.
  • Có thể restore chọn lọc.
  • Hỗ trợ parallel restore.

Với quy trình trong bài này, dùng custom archive.

Bước 4: Kiểm tra tương thích phiên bản

Kiểm tra:

pg_dump --version

Nguyên tắc quan trọng:

  • pg_dump có thể dump server PostgreSQL cũ hơn nó trong phạm vi được hỗ trợ.
  • pg_dump không dump được server có major version mới hơn chính nó.
  • Restore sang PostgreSQL mới hơn thường là hướng được hỗ trợ tốt hơn.
  • Restore ngược về major version cũ hơn không được đảm bảo.

Ví dụ, nếu server là PostgreSQL 18 nhưng máy chạy script chỉ có pg_dump 16, lệnh sẽ từ chối thực hiện.

Trên Ubuntu, hãy cài client đúng major version cần dùng từ nguồn package phù hợp với hệ thống của bạn.

Bước 5: Tạo tài khoản backup

Không nhất thiết phải dùng tài khoản superuser cho một logical backup thông thường.

Đăng nhập bằng tài khoản quản trị:

sudo -u postgres psql

Tạo role:

CREATE ROLE backup_user
WITH LOGIN
PASSWORD 'THAY_BANG_MAT_KHAU_MANH';

Cho phép kết nối:

GRANT CONNECT ON DATABASE appdb TO backup_user;

Chuyển vào database:

\c appdb

Cấp quyền cho schema public:

GRANT USAGE ON SCHEMA public TO backup_user;

GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_user;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO backup_user;

Áp dụng cho object tạo sau này:

ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO backup_user;

ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON SEQUENCES TO backup_user;

Nếu ứng dụng dùng nhiều schema, hãy cấp quyền cho từng schema cần backup.

Lưu ý: Quyền cần thiết phụ thuộc cấu trúc database, extension, Row-Level Security và ownership. Hãy chạy thử pg_dump bằng chính tài khoản backup và xử lý từng lỗi quyền thay vì cấp superuser ngay từ đầu.

Bước 6: Tạo user Linux dành cho backup

Tạo system user không có shell đăng nhập:

sudo useradd \
  --system \
  --create-home \
  --home-dir /var/lib/postgresql-backup \
  --shell /usr/sbin/nologin \
  backupsvc

Kiểm tra:

id backupsvc
sudo -u backupsvc sh -c 'echo "$HOME"'

Mục đích:

  • Tách file và credential backup khỏi user deploy.
  • Hạn chế quyền.
  • Dễ theo dõi cron và log.
  • Dễ thu hồi quyền khi cần.

Bước 7: Cấu hình .pgpass

Tạo file:

sudo -u backupsvc nano /var/lib/postgresql-backup/.pgpass

Nội dung:

127.0.0.1:5432:appdb:backup_user:THAY_BANG_MAT_KHAU_MANH

Đặt permission:

sudo chown backupsvc:backupsvc \
  /var/lib/postgresql-backup/.pgpass

sudo chmod 600 \
  /var/lib/postgresql-backup/.pgpass

PostgreSQL yêu cầu file password trên Unix không cho group hoặc user khác truy cập. Nếu permission quá rộng, file có thể bị bỏ qua.

Test:

sudo -u backupsvc \
  psql \
  -h 127.0.0.1 \
  -p 5432 \
  -U backup_user \
  -d appdb \
  -c "SELECT current_database(), current_user;"

Không đặt:

PGPASSWORD=mat_khau pg_dump ...

trực tiếp trong cron nếu có lựa chọn an toàn hơn.

Bước 8: Tạo thư mục backup và log

sudo mkdir -p \
  /var/backups/postgresql/appdb \
  /var/log/postgresql-backup

Gán owner:

sudo chown -R backupsvc:backupsvc \
  /var/backups/postgresql \
  /var/log/postgresql-backup

Đặt permission:

sudo chmod 700 /var/backups/postgresql
sudo chmod 700 /var/backups/postgresql/appdb
sudo chmod 750 /var/log/postgresql-backup

Kiểm tra dung lượng:

df -h /var/backups/postgresql
df -i /var/backups/postgresql

Không để backup chiếm hết ổ đĩa của database.

Bước 9: Chạy backup thủ công

Chạy dưới đúng Linux user:

sudo -u backupsvc \
  pg_dump \
  -h 127.0.0.1 \
  -p 5432 \
  -U backup_user \
  -d appdb \
  -Fc \
  --verbose \
  -f /var/backups/postgresql/appdb/appdb-manual.dump

Kiểm tra exit code ngay sau lệnh:

echo $?

Kết quả thành công:

0

Kiểm tra file:

sudo -u backupsvc \
  ls -lh /var/backups/postgresql/appdb/appdb-manual.dump

Không đánh giá thành công chỉ dựa vào việc file tồn tại. Một process thất bại vẫn có thể để lại file chưa hoàn chỉnh.

Bước 10: Kiểm tra archive và checksum

Liệt kê nội dung archive:

sudo -u backupsvc \
  pg_restore \
  --list \
  /var/backups/postgresql/appdb/appdb-manual.dump \
  > /dev/null

Sinh checksum:

sudo -u backupsvc \
  sha256sum \
  /var/backups/postgresql/appdb/appdb-manual.dump \
  > /var/backups/postgresql/appdb/appdb-manual.dump.sha256

Xác minh:

cd /var/backups/postgresql/appdb

sudo -u backupsvc \
  sha256sum --check appdb-manual.dump.sha256

Checksum giúp phát hiện file thay đổi hoặc hỏng trong quá trình sao chép. Nó không thay thế restore test.

Bước 11: Backup role và object toàn cluster

pg_dump chỉ backup một database. Nó không tự chứa đầy đủ role và tablespace ở cấp cluster.

Backup global object:

sudo -u postgres \
  pg_dumpall \
  --globals-only \
  > /var/backups/postgresql/appdb/globals.sql

Hạn chế permission:

sudo chown backupsvc:backupsvc \
  /var/backups/postgresql/appdb/globals.sql

sudo chmod 600 \
  /var/backups/postgresql/appdb/globals.sql

File global có thể chứa thông tin nhạy cảm như role definition và password hash. Hãy bảo vệ nó như một secret.

Nếu backup script chạy bằng backupsvc, cần thiết kế quyền phù hợp hoặc tách job global object thành một job quản trị riêng. Không cấp quyền hệ thống quá rộng chỉ để tiện chạy một lệnh.

Bước 12: Viết script backup an toàn

Tạo file:

sudo nano /usr/local/sbin/backup-postgresql-appdb.sh

Nội dung:

#!/usr/bin/env bash

set -Eeuo pipefail
umask 077

DB_HOST="127.0.0.1"
DB_PORT="5432"
DB_NAME="appdb"
DB_USER="backup_user"

BACKUP_DIR="/var/backups/postgresql/appdb"
LOG_DIR="/var/log/postgresql-backup"
RETENTION_DAYS="14"

TIMESTAMP="$(date '+%Y-%m-%d_%H-%M-%S')"
TEMP_FILE="${BACKUP_DIR}/.${DB_NAME}_${TIMESTAMP}.dump.tmp"
FINAL_FILE="${BACKUP_DIR}/${DB_NAME}_${TIMESTAMP}.dump"
CHECKSUM_FILE="${FINAL_FILE}.sha256"
LOG_FILE="${LOG_DIR}/backup.log"

mkdir -p "${BACKUP_DIR}" "${LOG_DIR}"

exec 9>"/var/lock/postgresql-appdb-backup.lock"

if ! flock -n 9; then
  printf '%s %s\n' \
    "$(date --iso-8601=seconds)" \
    "ERROR: another backup job is running" \
    >> "${LOG_FILE}"
  exit 1
fi

cleanup() {
  rm -f "${TEMP_FILE}"
}

trap cleanup EXIT

printf '%s %s\n' \
  "$(date --iso-8601=seconds)" \
  "INFO: backup started" \
  >> "${LOG_FILE}"

pg_dump \
  -h "${DB_HOST}" \
  -p "${DB_PORT}" \
  -U "${DB_USER}" \
  -d "${DB_NAME}" \
  -Fc \
  --verbose \
  -f "${TEMP_FILE}" \
  2>> "${LOG_FILE}"

pg_restore --list "${TEMP_FILE}" > /dev/null

mv "${TEMP_FILE}" "${FINAL_FILE}"

(
  cd "${BACKUP_DIR}"
  sha256sum "$(basename "${FINAL_FILE}")" \
    > "$(basename "${CHECKSUM_FILE}")"
)

find "${BACKUP_DIR}" \
  -type f \
  \( -name "${DB_NAME}_*.dump" -o -name "${DB_NAME}_*.dump.sha256" \) \
  -mtime "+${RETENTION_DAYS}" \
  -delete

printf '%s %s %s\n' \
  "$(date --iso-8601=seconds)" \
  "INFO: backup completed" \
  "${FINAL_FILE}" \
  >> "${LOG_FILE"

Dòng cuối phải đóng biến đúng cú pháp. Hãy dùng phiên bản hoàn chỉnh sau:

printf '%s %s %s\n' \
  "$(date --iso-8601=seconds)" \
  "INFO: backup completed" \
  "${FINAL_FILE}" \
  >> "${LOG_FILE}"

Vì sao script dùng file tạm?

.dump.tmp → backup đang chạy
.dump     → backup đã hoàn tất kiểm tra cơ bản

Nếu pg_dump thất bại, trap xóa file tạm. Job khác không nhầm file dở dang là bản backup hoàn chỉnh.

Vì sao dùng flock?

flock ngăn hai lần backup chạy cùng lúc, ví dụ job trước chưa xong nhưng cron đã kích hoạt job tiếp theo.

Cấp quyền thực thi:

sudo chmod 750 \
  /usr/local/sbin/backup-postgresql-appdb.sh

sudo chown root:backupsvc \
  /usr/local/sbin/backup-postgresql-appdb.sh

Bước 13: Kiểm tra script trước khi lên lịch

Kiểm tra cú pháp:

sudo bash -n \
  /usr/local/sbin/backup-postgresql-appdb.sh

Chạy bằng đúng user:

sudo -u backupsvc \
  /usr/local/sbin/backup-postgresql-appdb.sh

Xem log:

sudo tail -n 100 \
  /var/log/postgresql-backup/backup.log

Xem file:

sudo ls -lh \
  /var/backups/postgresql/appdb

Xác minh checksum mới nhất:

cd /var/backups/postgresql/appdb

LATEST_CHECKSUM="$(
  find . -maxdepth 1 -type f -name '*.sha256' \
  -printf '%T@ %p\n' |
  sort -nr |
  head -n 1 |
  cut -d' ' -f2-
)"

sudo -u backupsvc \
  sha256sum --check "${LATEST_CHECKSUM}"

Không cấu hình cron trước khi lệnh thủ công chạy thành công.

Bước 14: Lên lịch bằng cron

Tạo file:

sudo nano /etc/cron.d/postgresql-appdb-backup

Nội dung:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

15 2 * * * backupsvc /usr/local/sbin/backup-postgresql-appdb.sh >> /var/log/postgresql-backup/cron.log 2>&1

Job chạy lúc 02:15 mỗi ngày theo timezone của server.

Kiểm tra timezone:

timedatectl
date

Kiểm tra cron:

sudo systemctl status cron
sudo journalctl -u cron --since today

Kiểm tra file:

sudo chmod 644 \
  /etc/cron.d/postgresql-appdb-backup

sudo chown root:root \
  /etc/cron.d/postgresql-appdb-backup

Cron có môi trường tối giản. Vì vậy script nên dùng path rõ ràng và không phụ thuộc vào biến shell của user đăng nhập.

Bước 15: Cấu hình retention

Ví dụ trong script giữ file 14 ngày:

RETENTION_DAYS="14"

Chính sách retention gợi ý:

7 bản hàng ngày
4 bản hàng tuần
6 bản hàng tháng

Không có một con số đúng cho mọi dự án. Chính sách phụ thuộc:

  • Dung lượng database.
  • Tần suất thay đổi.
  • Yêu cầu pháp lý.
  • Chi phí storage.
  • Khả năng phát hiện lỗi trễ.
  • RPO và RTO.

Trước khi dùng find ... -delete, chạy thử không có -delete:

find /var/backups/postgresql/appdb \
  -type f \
  -mtime +14 \
  -print

Chỉ bật xóa sau khi danh sách đúng.

Bước 16: Sao chép backup ra khỏi VPS

Backup chỉ nằm trên cùng VPS không bảo vệ được khi:

  • VPS bị xóa.
  • Ổ đĩa hỏng.
  • Tài khoản cloud bị chiếm.
  • Ransomware mã hóa dữ liệu.
  • Script sai xóa cả database và backup.
  • Nhà cung cấp gặp sự cố.

Có thể sao chép sang máy backup riêng bằng rsync:

rsync -az \
  --partial \
  /var/backups/postgresql/appdb/ \
  backup@backup-server:/srv/backups/appdb/

Hoặc dùng object storage có:

Versioning
Retention policy
Encryption
Lifecycle rule
Access log
Credential riêng cho backup

Không dùng cùng credential có quyền xóa toàn bộ production nếu không cần thiết.

Mô hình tối thiểu:

1 bản trên VPS để restore nhanh
1 bản ngoài VPS để chống mất máy chủ
Nhiều phiên bản theo thời gian

Bước 17: Restore thử vào database riêng

Không restore đè production để kiểm tra.

Tạo database thử từ template0:

sudo -u postgres \
  createdb \
  -T template0 \
  appdb_restore_test

Chọn file backup:

LATEST_DUMP="$(
  find /var/backups/postgresql/appdb \
  -maxdepth 1 \
  -type f \
  -name 'appdb_*.dump' \
  -printf '%T@ %p\n' |
  sort -nr |
  head -n 1 |
  cut -d' ' -f2-
)"

echo "${LATEST_DUMP}"

Restore:

sudo -u postgres \
  pg_restore \
  --dbname=appdb_restore_test \
  --no-owner \
  --no-privileges \
  --exit-on-error \
  "${LATEST_DUMP}"

Cập nhật statistics:

sudo -u postgres \
  psql \
  -d appdb_restore_test \
  -c "ANALYZE;"

Kiểm tra:

sudo -u postgres \
  psql \
  -d appdb_restore_test \
  -c "\dt"

Ví dụ kiểm tra số dòng:

sudo -u postgres \
  psql \
  -d appdb_restore_test \
  -c "SELECT COUNT(*) FROM users;"

Sau khi xác nhận:

sudo -u postgres \
  dropdb appdb_restore_test

Restore test nên kiểm tra ít nhất:

Archive đọc được
Schema được tạo
Dữ liệu quan trọng có mặt
Migration version đúng
Ứng dụng có thể kết nối
Một số truy vấn nghiệp vụ chạy đúng
Thời gian restore được ghi lại

Bước 18: Diễn tập phục hồi đầy đủ

Một restore drill tốt không chỉ chạy pg_restore trên cùng VPS.

Hãy thử kịch bản:

1. Tạo một VPS hoặc máy test sạch
2. Cài đúng major version PostgreSQL
3. Khôi phục role cần thiết
4. Tải backup từ kho ngoài VPS
5. Xác minh checksum
6. Tạo database từ template0
7. Chạy pg_restore
8. Chạy ANALYZE
9. Cập nhật secret của ứng dụng test
10. Chạy smoke test
11. Ghi thời gian từng bước
12. Cập nhật runbook

Kết quả cần ghi:

Ngày test:
File backup:
Dung lượng:
Thời gian tải:
Thời gian restore:
Tổng RTO:
Lỗi gặp phải:
Cách xử lý:
Người xác nhận:

Trường hợp PostgreSQL chạy trong Docker Compose

Xác định service:

docker compose ps

Backup từ container:

mkdir -p /var/backups/postgresql/appdb

docker compose exec -T postgres \
  pg_dump \
  -U postgres \
  -d appdb \
  -Fc \
  > /var/backups/postgresql/appdb/appdb-docker.dump

Dấu > được shell trên host xử lý, nên file nằm trên host.

Kiểm tra:

docker compose exec -T postgres \
  pg_restore --list \
  < /var/backups/postgresql/appdb/appdb-docker.dump \
  > /dev/null

Restore vào database test trong container:

docker compose exec -T postgres \
  createdb \
  -U postgres \
  -T template0 \
  appdb_restore_test
docker compose exec -T postgres \
  pg_restore \
  -U postgres \
  -d appdb_restore_test \
  --no-owner \
  --no-privileges \
  --exit-on-error \
  < /var/backups/postgresql/appdb/appdb-docker.dump

Không chỉ copy thư mục data của container khi PostgreSQL đang chạy rồi xem đó là backup hợp lệ. Physical backup cần quy trình đảm bảo tính nhất quán riêng.

Monitoring backup tối thiểu

Theo dõi:

Lần backup thành công gần nhất
Exit code
Dung lượng file
Thời gian chạy
Dung lượng ổ đĩa
Số bản đang giữ
Kết quả sao chép offsite
Kết quả restore test gần nhất

Xem log:

sudo tail -f \
  /var/log/postgresql-backup/backup.log

Tìm lỗi:

sudo grep -iE \
  'error|fatal|failed' \
  /var/log/postgresql-backup/*.log

Kiểm tra file mới nhất:

find /var/backups/postgresql/appdb \
  -maxdepth 1 \
  -type f \
  -name '*.dump' \
  -printf '%TY-%Tm-%Td %TH:%TM %s %p\n' |
sort -r |
head

Một job không tạo backup trong khoảng thời gian dự kiến phải phát cảnh báo.

Những việc không nên làm

Chỉ kiểm tra file có tồn tại

File có thể rỗng, chưa hoàn chỉnh hoặc chứa archive lỗi.

Ghi password vào script

Script thường được backup, đọc bởi nhiều user hoặc vô tình commit.

Chỉ giữ một bản mới nhất

Nếu lỗi dữ liệu đã xảy ra vài ngày trước, bản mới nhất có thể đã chứa lỗi.

Chỉ lưu trên cùng VPS

Mất VPS đồng nghĩa mất cả database lẫn backup.

Không restore thử

pg_restore --list chỉ là kiểm tra cơ bản, không chứng minh ứng dụng chạy được sau restore.

Cho backup user quyền superuser mặc định

Hãy bắt đầu với quyền tối thiểu và chỉ tăng khi có lý do rõ ràng.

Chạy retention trước khi backup hoàn tất

Nếu job lỗi sau khi xóa bản cũ, số bản an toàn có thể giảm ngoài dự kiến.

Checklist production

[ ] Đã ghi RPO và RTO
[ ] Client pg_dump tương thích server
[ ] Có tài khoản backup riêng hoặc cơ chế quyền rõ ràng
[ ] Password không nằm trong script
[ ] .pgpass có permission 600
[ ] Thư mục backup không public
[ ] Backup dùng file tạm
[ ] Script dùng set -Eeuo pipefail
[ ] Có flock chống chạy trùng
[ ] Kiểm tra exit code
[ ] pg_restore --list chạy thành công
[ ] Có checksum
[ ] Có retention
[ ] Có log
[ ] Cron chạy bằng user riêng
[ ] Có bản sao ngoài VPS
[ ] Global object được xem xét
[ ] Restore test chạy thành công
[ ] Có runbook phục hồi
[ ] Có cảnh báo khi backup trễ hoặc thất bại

Câu hỏi thường gặp

pg_dump có làm khóa database không?

pg_dump tạo export nhất quán trong khi database vẫn có thể được sử dụng. Nó không chặn thao tác đọc hoặc ghi thông thường, nhưng vẫn cần các lock phù hợp để bảo vệ object trong lúc dump. DDL hoặc yêu cầu exclusive lock có thể ảnh hưởng tới quá trình backup.

Nên backup bao lâu một lần?

Dựa vào RPO. Nếu chấp nhận mất tối đa một giờ dữ liệu, lịch backup một lần mỗi ngày là không đủ.

Dùng .sql hay .dump?

Dùng plain SQL khi cần file dễ đọc và restore bằng psql. Dùng custom archive khi cần nén, xem danh sách object, restore chọn lọc hoặc parallel restore.

pg_dump có backup role không?

Không đầy đủ. Role và tablespace là global object. Hãy xem xét pg_dumpall --globals-only.

Có thể restore backup sang PostgreSQL cũ hơn không?

Không nên giả định sẽ thành công. Khả năng restore về major version cũ hơn không được đảm bảo.

Checksum thành công có nghĩa backup dùng được không?

Không. Checksum chỉ cho biết file chưa thay đổi so với lúc tạo checksum. Vẫn phải restore thử.

pg_dump có đủ cho mọi hệ thống production không?

Không. Với database lớn, RPO thấp hoặc cần Point-in-Time Recovery, hãy đánh giá physical backup và WAL archiving hoặc dùng dịch vụ PostgreSQL được quản lý.

Bài viết liên quan

Kết luận

Một quy trình backup PostgreSQL production cần trả lời được ba câu hỏi:

Backup có chạy đúng lịch không?
File có được lưu an toàn ngoài VPS không?
Đã restore thành công gần đây chưa?

pg_dump, cron và checksum tạo nền tảng tốt cho ứng dụng nhỏ và vừa. Tuy nhiên, mục tiêu cuối cùng không phải là có nhiều file backup, mà là khôi phục được dịch vụ trong RPO và RTO đã cam kết.

Nguồn tham khảo

Đọc tiếp