Hướng Dẫn Toàn Diện về Backup và Restore PostgreSQL
Bài viết này sẽ giúp bạn nắm vững các phương pháp backup và restore PostgreSQL từ cơ bản đến nâng cao, kèm theo các best practices trong thực tế.
Tại Sao Backup Quan Trọng?
Trước khi đi vào chi tiết kỹ thuật, hãy cùng nhìn lại một câu chuyện có thật: Một startup công nghệ tại Việt Nam từng mất toàn bộ dữ liệu khách hàng vì không có backup đúng cách. Hệ quả? Họ mất 6 tháng để phục hồi niềm tin từ khách hàng và gần như phá sản.
Backup không chỉ là một công việc kỹ thuật, mà là một chiến lược bảo vệ doanh nghiệp của bạn.
Phần 1: Các Phương Pháp Backup PostgreSQL
1.1. Logical Backup với pg_dump
Đây là phương pháp phổ biến nhất, phù hợp cho hầu hết các trường hợp.
Backup một database đơn lẻ
# Format SQL plain text (dễ đọc, dễ edit)
pg_dump -U postgres -d myapp_db > myapp_backup.sql
# Format custom (nén tốt, restore linh hoạt)
pg_dump -U postgres -d myapp_db -F c -f myapp_backup.dump
# Format directory (backup song song, nhanh nhất)
pg_dump -U postgres -d myapp_db -F d -j 4 -f myapp_backup_dir/
So sánh các format:
| Format | Ưu điểm | Nhược điểm | Khi nào dùng |
|---|---|---|---|
| Plain SQL (-F p) | Dễ đọc, edit được | Không nén, restore chậm | Database nhỏ, cần xem nội dung |
| Custom (-F c) | Nén tốt, restore chọn lọc | Không đọc được trực tiếp | Hầu hết các trường hợp |
| Directory (-F d) | Backup song song, nhanh nhất | Tốn nhiều files | Database lớn (>100GB) |
| Tar (-F t) | Nén được | Không restore song song | Ít dùng |
Backup có chọn lọc
# Chỉ backup schema (cấu trúc tables, indexes, constraints)
pg_dump -U postgres -d myapp_db --schema-only > schema.sql
# Chỉ backup data
pg_dump -U postgres -d myapp_db --data-only > data.sql
# Backup một table cụ thể
pg_dump -U postgres -d myapp_db -t users -t orders > important_tables.sql
# Backup tất cả trừ table logs (thường rất lớn)
pg_dump -U postgres -d myapp_db -T logs > backup_no_logs.sql
# Backup theo schema
pg_dump -U postgres -d myapp_db -n public -n reporting > selected_schemas.sql
Ví dụ thực tế: Backup database production
#!/bin/bash
# Script: backup_production.sh
DB_NAME="myapp_production"
DB_USER="postgres"
DB_HOST="localhost"
BACKUP_DIR="/backups/postgresql"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.dump"
# Tạo thư mục nếu chưa có
mkdir -p $BACKUP_DIR
# Backup với compression level 9
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME \
-F c -Z 9 \
-f $BACKUP_FILE \
--verbose
# Check kết quả
if [ $? -eq 0 ]; then
echo "✓ Backup thành công: $BACKUP_FILE"
SIZE=$(du -h $BACKUP_FILE | cut -f1)
echo "✓ Kích thước: $SIZE"
else
echo "✗ Backup thất bại!"
exit 1
fi
# Xóa backup cũ hơn 7 ngày
find $BACKUP_DIR -name "${DB_NAME}_*.dump" -mtime +7 -delete
echo "✓ Đã xóa backup cũ hơn 7 ngày"
1.2. Backup toàn bộ cluster với pg_dumpall
Khi bạn cần backup tất cả databases, roles, và tablespaces:
# Backup toàn bộ
pg_dumpall -U postgres > all_databases.sql
# Chỉ backup global objects (roles, tablespaces)
pg_dumpall -U postgres --globals-only > globals.sql
# Chỉ backup roles
pg_dumpall -U postgres --roles-only > roles.sql
Khi nào dùng pg_dumpall?
- Khi migrate toàn bộ PostgreSQL server sang máy mới
- Khi cần backup cả user permissions và roles
- Khi có nhiều databases liên quan đến nhau
1.3. Physical Backup với Base Backup
Đây là phương pháp backup ở mức file system, phù hợp cho databases rất lớn.
# Bước 1: Tạo base backup
pg_basebackup -U postgres -D /backups/base -F tar -z -P
# Bước 2: Configure WAL archiving (trong postgresql.conf)
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /backups/wal/%f && cp %p /backups/wal/%f'
max_wal_senders = 3
Ưu điểm:
- Rất nhanh cho database lớn (TB-level)
- Hỗ trợ Point-in-Time Recovery (PITR)
- Có thể dùng cho replication
Nhược điểm:
- Phức tạp hơn logical backup
- Phải backup cả cluster, không thể chọn database riêng lẻ
- Yêu cầu cùng phiên bản PostgreSQL khi restore
Phần 2: Restore PostgreSQL
2.1. Restore từ SQL file
# Tạo database mới (nếu cần)
createdb -U postgres myapp_db_restored
# Restore từ SQL file
psql -U postgres -d myapp_db_restored < myapp_backup.sql
# Restore với error handling
psql -U postgres -d myapp_db_restored \
-v ON_ERROR_STOP=1 \
--echo-errors \
< myapp_backup.sql
2.2. Restore từ Custom/Directory format
# Restore cơ bản
pg_restore -U postgres -d myapp_db myapp_backup.dump
# Restore với clean (xóa objects cũ trước)
pg_restore -U postgres -d myapp_db -c myapp_backup.dump
# Restore song song (nhanh hơn nhiều)
pg_restore -U postgres -d myapp_db -j 4 myapp_backup.dump
# Restore chỉ một table
pg_restore -U postgres -d myapp_db -t users myapp_backup.dump
# Restore vào database mới
pg_restore -U postgres -d postgres -C myapp_backup.dump
2.3. Restore Script hoàn chỉnh
#!/bin/bash
# Script: restore_database.sh
BACKUP_FILE=$1
NEW_DB_NAME=$2
if [ -z "$BACKUP_FILE" ] || [ -z "$NEW_DB_NAME" ]; then
echo "Usage: $0 <backup_file> <new_db_name>"
exit 1
fi
echo "→ Kiểm tra file backup..."
if [ ! -f "$BACKUP_FILE" ]; then
echo "✗ File không tồn tại: $BACKUP_FILE"
exit 1
fi
echo "→ Tạo database mới: $NEW_DB_NAME"
createdb -U postgres $NEW_DB_NAME
if [ $? -ne 0 ]; then
echo "✗ Không thể tạo database"
exit 1
fi
echo "→ Đang restore..."
pg_restore -U postgres -d $NEW_DB_NAME -j 4 --verbose $BACKUP_FILE
if [ $? -eq 0 ]; then
echo "✓ Restore thành công!"
echo "→ Thông tin database:"
psql -U postgres -d $NEW_DB_NAME -c "\dt"
else
echo "✗ Restore thất bại!"
exit 1
fi
Phần 3: Strategies và Best Practices
3.1. Chiến lược Backup 3-2-1
Đây là quy tắc vàng trong backup:
- 3 bản copies của dữ liệu
- 2 loại media khác nhau (ví dụ: disk và cloud)
- 1 bản offsite (ở vị trí vật lý khác)
Ví dụ implementation:
#!/bin/bash
# Script: backup_strategy_321.sh
DB_NAME="myapp_production"
LOCAL_BACKUP="/backups/local"
NAS_BACKUP="/mnt/nas/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="${DB_NAME}_${DATE}.dump"
# Backup 1: Local disk
echo "→ Creating local backup..."
pg_dump -U postgres -d $DB_NAME -F c -f "$LOCAL_BACKUP/$BACKUP_NAME"
# Backup 2: NAS (different media)
echo "→ Copying to NAS..."
cp "$LOCAL_BACKUP/$BACKUP_NAME" "$NAS_BACKUP/"
# Backup 3: Cloud (offsite) - AWS S3
echo "→ Uploading to S3..."
aws s3 cp "$LOCAL_BACKUP/$BACKUP_NAME" \
s3://mycompany-backups/postgresql/ \
--storage-class STANDARD_IA
echo "✓ 3-2-1 backup completed!"
3.2. Backup Schedule
Đề xuất lịch backup cho các môi trường khác nhau:
Development:
# Crontab: Backup hàng ngày lúc 2 giờ sáng
0 2 * * * /scripts/backup_dev.sh
Staging:
# Backup mỗi 6 giờ
0 */6 * * * /scripts/backup_staging.sh
Production:
# Full backup: Mỗi ngày lúc 2 giờ sáng
0 2 * * * /scripts/full_backup_prod.sh
# Incremental backup: Mỗi giờ
0 * * * * /scripts/incremental_backup_prod.sh
# WAL archiving: Continuous
3.3. Tự động hóa với systemd timer
# /etc/systemd/system/postgresql-backup.service
[Unit]
Description=PostgreSQL Backup Service
After=postgresql.service
[Service]
Type=oneshot
User=postgres
ExecStart=/usr/local/bin/backup_postgres.sh
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/postgresql-backup.timer
[Unit]
Description=PostgreSQL Daily Backup Timer
[Timer]
OnCalendar=daily
OnCalendar=02:00
Persistent=true
[Install]
WantedBy=timers.target
Enable timer:
sudo systemctl enable postgresql-backup.timer
sudo systemctl start postgresql-backup.timer
3.4. Monitoring và Alerting
Script kiểm tra backup:
#!/bin/bash
# Script: check_backup_health.sh
BACKUP_DIR="/backups/postgresql"
MAX_AGE_HOURS=24
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
# Tìm backup mới nhất
LATEST_BACKUP=$(find $BACKUP_DIR -name "*.dump" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" ")
if [ -z "$LATEST_BACKUP" ]; then
MESSAGE="⚠️ CẢNH BÁO: Không tìm thấy backup nào!"
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$MESSAGE\"}" \
$SLACK_WEBHOOK
exit 1
fi
# Kiểm tra tuổi của backup
BACKUP_TIME=$(stat -c %Y "$LATEST_BACKUP")
CURRENT_TIME=$(date +%s)
AGE_HOURS=$(( ($CURRENT_TIME - $BACKUP_TIME) / 3600 ))
if [ $AGE_HOURS -gt $MAX_AGE_HOURS ]; then
MESSAGE="⚠️ CẢNH BÁO: Backup quá cũ! Age: ${AGE_HOURS}h\nFile: $LATEST_BACKUP"
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$MESSAGE\"}" \
$SLACK_WEBHOOK
exit 1
fi
# Kiểm tra kích thước backup (phải > 0)
SIZE=$(stat -c %s "$LATEST_BACKUP")
if [ $SIZE -eq 0 ]; then
MESSAGE="⚠️ CẢNH BÁO: Backup có kích thước 0 bytes!\nFile: $LATEST_BACKUP"
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$MESSAGE\"}" \
$SLACK_WEBHOOK
exit 1
fi
echo "✓ Backup health check passed"
echo " Latest: $LATEST_BACKUP"
echo " Age: ${AGE_HOURS}h"
echo " Size: $(du -h $LATEST_BACKUP | cut -f1)"
3.5. Testing Restore
QUAN TRỌNG: Backup không có giá trị nếu bạn chưa bao giờ test restore!
#!/bin/bash
# Script: test_restore.sh
BACKUP_FILE=$1
TEST_DB="test_restore_$(date +%s)"
echo "→ Testing restore from: $BACKUP_FILE"
# Tạo test database
createdb -U postgres $TEST_DB
# Restore
pg_restore -U postgres -d $TEST_DB $BACKUP_FILE
# Kiểm tra
TABLES=$(psql -U postgres -d $TEST_DB -t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public'")
if [ $TABLES -gt 0 ]; then
echo "✓ Restore test PASSED: $TABLES tables restored"
# Verify data
psql -U postgres -d $TEST_DB -c "SELECT tablename, n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 10"
else
echo "✗ Restore test FAILED: No tables found"
fi
# Cleanup
dropdb -U postgres $TEST_DB
echo "✓ Test completed and cleaned up"
Phần 4: Troubleshooting
4.1. Lỗi thường gặp khi Backup
Lỗi: "permission denied"
# Solution: Chạy với user có quyền
sudo -u postgres pg_dump mydb > backup.sql
# Hoặc grant quyền
GRANT CONNECT ON DATABASE mydb TO backup_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_user;
Lỗi: "could not connect to server"
# Kiểm tra PostgreSQL đang chạy
sudo systemctl status postgresql
# Kiểm tra port
netstat -tlnp | grep 5432
# Kiểm tra pg_hba.conf
sudo vim /etc/postgresql/14/main/pg_hba.conf
Lỗi: Backup quá lâu
# Solution: Dùng format directory với parallel
pg_dump -F d -j 8 -f backup_dir/ mydb
# Hoặc exclude tables lớn
pg_dump -T large_log_table mydb > backup.sql
4.2. Lỗi thường gặp khi Restore
Lỗi: "database already exists"
# Solution 1: Drop database cũ
dropdb mydb
createdb mydb
pg_restore -d mydb backup.dump
# Solution 2: Dùng flag -c (clean)
pg_restore -c -d mydb backup.dump
Lỗi: "role does not exist"
# Solution: Restore roles trước
pg_dumpall --roles-only > roles.sql
psql -f roles.sql
# Sau đó restore data
pg_restore -d mydb backup.dump
Lỗi: Out of disk space
# Check disk space trước khi restore
df -h
# Ước tính kích thước cần thiết (thường 2-3x backup file)
du -h backup.dump
Phần 5: Advanced Topics
5.1. Point-in-Time Recovery (PITR)
PITR cho phép bạn restore database về một thời điểm cụ thể trong quá khứ.
Setup WAL archiving:
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /wal_archive/%f && cp %p /wal_archive/%f'
archive_timeout = 300 # Force WAL rotation every 5 minutes
Thực hiện PITR:
# Bước 1: Stop PostgreSQL
sudo systemctl stop postgresql
# Bước 2: Restore base backup
rm -rf /var/lib/postgresql/14/main/*
tar -xzf /backups/base.tar.gz -C /var/lib/postgresql/14/main/
# Bước 3: Tạo recovery.conf (PostgreSQL < 12) hoặc recovery.signal (>= 12)
cat > /var/lib/postgresql/14/main/recovery.signal << EOF
restore_command = 'cp /wal_archive/%f %p'
recovery_target_time = '2024-01-15 14:30:00'
recovery_target_action = 'promote'
EOF
# Bước 4: Start PostgreSQL
sudo systemctl start postgresql
5.2. Continuous Archiving với pgBackRest
pgBackRest là công cụ backup enterprise-grade cho PostgreSQL:
# Cài đặt
sudo apt-get install pgbackrest
# Config /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
[mydb]
pg1-path=/var/lib/postgresql/14/main
# Full backup
pgbackrest --stanza=mydb --type=full backup
# Incremental backup
pgbackrest --stanza=mydb --type=incr backup
# Restore
pgbackrest --stanza=mydb restore
5.3. Backup với Docker
# Backup PostgreSQL trong Docker
docker exec my_postgres_container pg_dump -U postgres mydb > backup.sql
# Restore
docker exec -i my_postgres_container psql -U postgres mydb < backup.sql
# Docker Compose với automated backups
version: '3.8'
services:
postgres:
image: postgres:14
volumes:
- postgres_data:/var/lib/postgresql/data
backup:
image: prodrigestivill/postgres-backup-local
environment:
POSTGRES_HOST: postgres
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
SCHEDULE: "@daily"
volumes:
- ./backups:/backups
Kết Luận
Backup và restore không chỉ là một task kỹ thuật đơn thuần, mà là một phần quan trọng trong chiến lược bảo vệ dữ liệu của doanh nghiệp. Một số điểm quan trọng cần nhớ:
- Luôn test restore - Backup chưa test = không có backup
- Automate everything - Đừng dựa vào việc nhớ chạy backup thủ công
- Follow 3-2-1 rule - 3 copies, 2 media types, 1 offsite
- Monitor và alert - Biết ngay khi có vấn đề
- Document everything - Team mới cũng phải biết cách restore
Checklist cuối cùng
- [ ] Backup script đã được viết và test
- [ ] Crontab/systemd timer đã được setup
- [ ] Monitoring và alerting đã được cấu hình
- [ ] Restore đã được test ít nhất 1 lần
- [ ] Documentation đã được viết
- [ ] Team đã được training về quy trình backup/restore
- [ ] Offsite backup đã được setup
- [ ] Retention policy đã được định nghĩa rõ ràng
Nguồn tham khảo:
- PostgreSQL Official Documentation - Backup and Restore
- pgBackRest Documentation
- PostgreSQL Backup Best Practices
Bài viết này được cập nhật lần cuối: Tháng 12, 2024