為什麼備份很重要?
在討論技術細節之前,讓我們先回顧一個真實的故事:越南的一家科技新創公司曾經因為沒有適當的備份而失去了所有客戶資料。結果?他們花了 6 個月的時間才恢復了客戶的信任,差點破產。
備份不僅是一項技術工作,更是保護您業務的策略。
第 1 部分:PostgreSQL 備份方法
1.1.使用 pg_dump 進行邏輯備份
這是最常用的方法,適用於大多數情況。
備份單一資料庫
# Format SQL plain text (dễ đọc, dễ edit) pg_dump -U postgres -d myapp_db > myapp_backup.sqlFormat 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/
比較格式:
| 格式 | 優點 | 缺點 | 何時使用 |
|---|---|---|---|
| 普通 SQL (-F p) | 易於閱讀和編輯 | 無壓縮,恢復速度慢 | 資料庫較小,需要查看內容 |
| 自訂 (-F c) | 良好的壓縮,選擇性恢復 | 無法直接讀取 | 大多數情況 |
| 目錄 (-F d) | 並行備份,最快 | 需要很多文件 | 大型資料庫(>100GB) |
| 焦油 (-F t) | 可壓縮 | 不要並行恢復 | 很少使用 |
選擇性備份
# Chỉ backup schema (cấu trúc tables, indexes, constraints) pg_dump -U postgres -d myapp_db --schema-only > schema.sqlChỉ 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
實例:備份資料庫製作
#!/bin/bashScript: 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
--verboseCheck 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.使用pg_dumpall備份整個集群
當您需要備份所有資料庫、角色和表空間時:
# Backup toàn bộ pg_dumpall -U postgres > all_databases.sqlChỉ backup global objects (roles, tablespaces)
pg_dumpall -U postgres --globals-only > globals.sql
Chỉ backup roles
pg_dumpall -U postgres --roles-only > roles.sql
何時使用 pg_dumpall?
- 將整個 PostgreSQL 伺服器遷移到新機器時
- 當您需要同時備份使用者權限和角色時
- 當有多個資料庫相互關聯時
1.3.實體備份與基礎備份
這是一種檔案系統層級的備份方法,適用於非常大的資料庫。
# Bước 1: Tạo base backup pg_basebackup -U postgres -D /backups/base -F tar -z -PBướ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
優點:
- 對於大型資料庫(TB 級)非常快
- 時間點恢復 (PITR) 支持
- 可用於複製
缺點:
- 比邏輯備份更複雜
- 必須備份整個集群,不能選擇單一資料庫
- 復原時需要相同的 PostgreSQL 版本
第 2 部分:復原 PostgreSQL
2.1.從 SQL 檔案恢復
# Tạo database mới (nếu cần) createdb -U postgres myapp_db_restoredRestore 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 cơ bản pg_restore -U postgres -d myapp_db myapp_backup.dumpRestore 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.恢復完整腳本
#!/bin/bashScript: 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
第 3 部分:策略與最佳實踐
3.1.備份策略3-2-1
這是備份的黃金法則:
- 3 資料的副本
- 2 不同的媒體類型(例如磁碟和雲端)
- 1 異地版本(在另一個實體位置)
實現範例:
#!/bin/bashScript: 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.備份計劃
針對不同環境的建議備份計畫:
發展:
# Crontab: Backup hàng ngày lúc 2 giờ sáng
0 2 * * * /scripts/backup_dev.sh
分期:
# Backup mỗi 6 giờ
0 */6 * * * /scripts/backup_staging.sh
生產:
# Full backup: Mỗi ngày lúc 2 giờ sáng 0 2 * * * /scripts/full_backup_prod.shIncremental backup: Mỗi giờ
0 * * * * /scripts/incremental_backup_prod.sh
WAL archiving: Continuous
3.3.使用 systemd 計時器實現自動化
# /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
啟用定時器:
sudo systemctl enable postgresql-backup.timer
sudo systemctl start postgresql-backup.timer
3.4.監控和警報
檢查備份的腳本:
#!/bin/bashScript: 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 fiKiể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 fiKiể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.測試恢復
重要: 如果您從未測試過恢復,備份就沒有價值!
#!/bin/bashScript: 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"
第 4 部分:故障排除
4.1.備份時常見錯誤
錯誤:“權限被拒絕”
# Solution: Chạy với user có quyền sudo -u postgres pg_dump mydb > backup.sqlHoặc grant quyền
GRANT CONNECT ON DATABASE mydb TO backup_user; GRANT SELECT ON ALL TABLES IN SCHEMA public TO backup_user;
錯誤:“無法連接到伺服器”
# Kiểm tra PostgreSQL đang chạy sudo systemctl status postgresqlKiểm tra port
netstat -tlnp | grep 5432
Kiểm tra pg_hba.conf
sudo vim /etc/postgresql/14/main/pg_hba.conf
錯誤:備份時間太長
# Solution: Dùng format directory với parallel pg_dump -F d -j 8 -f backup_dir/ mydbHoặc exclude tables lớn
pg_dump -T large_log_table mydb > backup.sql
4.2.恢復時常見錯誤
錯誤:“資料庫已存在”
# Solution 1: Drop database cũ dropdb mydb createdb mydb pg_restore -d mydb backup.dumpSolution 2: Dùng flag -c (clean)
pg_restore -c -d mydb backup.dump
錯誤:“角色不存在”
# Solution: Restore roles trước pg_dumpall --roles-only > roles.sql psql -f roles.sqlSau đó restore data
pg_restore -d mydb backup.dump
錯誤:磁碟空間不足
# 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
第 5 部分:進階主題
5.1.時間點恢復 (PITR)
PITR 可讓您將資料庫還原到過去的特定時間。
設定 WAL 歸檔:
# 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
實施 PITR:
# Bước 1: Stop PostgreSQL sudo systemctl stop postgresqlBướ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.使用 pgBackRest 進行連續歸檔
pgBackRest 是 PostgreSQL 的企業級備份工具:
# Cài đặt sudo apt-get install pgbackrestConfig /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.使用 Docker 進行備份
# Backup PostgreSQL trong Docker docker exec my_postgres_container pg_dump -U postgres mydb > backup.sqlRestore
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
結論
備份和復原不僅是一項簡單的技術任務,也是企業資料保護策略的重要組成部分。需要記住的一些要點:
- 始終測試恢復 - 備份未測試 = 無備份
- 自動化一切 - 不要依賴記住運行手動備份
- 遵循 3-2-1 規則 - 3 份,2 種媒體類型,1 份異地
- 監控和警報 - 出現問題時立即知道
- 記錄一切 - 新團隊也必須懂得如何恢復
最終清單
- [ ] 備份腳本已編寫並測試
- [ ] crontab/systemd 定時器已設定
- [ ] 監控警報已配置
- [ ] 恢復已至少測試過一次
- [ ] 文檔已經寫好
- [ ] 團隊已接受備份/復原流程的培訓
- [ ] 設定異地備份
- [ ] 保留政策已明確定義
參考來源:
本文最後更新時間:2024 年 12 月
