Tập này xây hệ thống backup tự động cho ứng dụng quản lý chi tiêu: pg_dump mỗi đêm, đồng bộ media lên S3 hoặc MinIO, và diễn tập restore định kỳ để khi sự cố xảy ra bạn khôi phục được trong vài phút thay vì mất dữ liệu. Nối tiếp tập 14 về upload file an toàn, tập này bảo vệ chính những file và dữ liệu đã được upload đó — vì dữ liệu không có backup thì chỉ là dữ liệu đang chờ mất.
1. Backup PostgreSQL bằng pg_dump tự động
pg_dump tạo một file SQL chứa toàn bộ schema và dữ liệu của database. Chạy với cờ –no-owner và –no-acl để file restore được sang database khác mà không bị kẹt quyền sở hữu. Chạy backup lúc 2 giờ sáng, nén bằng gzip, đặt tên file theo ngày, giữ 7 bản gần nhất và xóa bản cũ bằng find -mtime +7. Đừng backup vào cùng ổ đĩa với database: copy file lên S3, MinIO hoặc một máy khác ngay sau khi dump xong. Mật khẩu truyền qua biến môi trường PGPASSWORD, không ghi vào script.
#!/bin/bashset -euo pipefailDATE=$(date +%Y%m%d)pg_dump --no-owner --no-acl -h "$DB_HOST" -U "$DB_USER" "$DB_NAME" \ | gzip > "/backup/db-$DATE.sql.gz"find /backup -name "db-*.sql.gz" -mtime +7 -deleteaws s3 cp "/backup/db-$DATE.sql.gz" "s3://my-backups/db/"
0 2 * * * /opt/app/backup.sh >> /var/log/backup.log 2>&1
2. Backup media và file upload
Media — ảnh đính kèm, file người dùng tải lên — không nằm trong pg_dump nên phải backup riêng. Dùng rclone sync hoặc aws s3 sync từ thư mục media lên một bucket riêng, bật versioning để khôi phục file bị ghi đè hoặc xóa nhầm. Nếu tự host MinIO, hãy snapshot cả volume chứa dữ liệu của nó. Kiểm tra dung lượng bucket mỗi tuần vì media tăng nhanh hơn bạn nghĩ.
3. Diễn tập restore định kỳ
Backup chưa từng restore thì chưa phải là backup. Mỗi tháng một lần, tạo một database trống, restore file backup mới nhất vào đó, chạy migrate –check rồi mở vài trang chính và đếm số bản ghi quan trọng. Đo thời gian restore và ghi lại: nếu restore mất hai giờ thì mục tiêu khôi phục trong 30 phút chỉ là ảo tưởng. Lưu quy trình restore thành runbook trong repo để bất kỳ ai trực ca cũng làm được lúc 3 giờ sáng.
gunzip -c /backup/db-20261110.sql.gz | psql -h localhost -U app restore_testpython manage.py migrate --check --database restore_test
Áp dụng vào dự án của bạn
Bắt đầu ngay tối nay: viết script backup cho database quản lý chi tiêu, đặt cron chạy 2 giờ sáng, đồng bộ media lên S3 và đặt lịch nhắc diễn tập restore vào ngày đầu tháng sau. Khi hệ thống đã chạy một tuần không lỗi, hãy thử xóa một giao dịch test rồi khôi phục từ backup để tự tin rằng mọi thứ thật sự hoạt động.
Bài viết liên quan
- Django vận hành production #14: Upload file và media an toàn — validate loại file, giới hạn dung lượng, signed URL
- Django vận hành production #4: PostgreSQL trên production — kết nối, CONN_MAX_AGE, pool với PgBouncer, backup cơ bản
- Django vận hành production #13: Rate limiting và chống abuse cho DRF (throttle, django-ratelimit)
Câu hỏi thường gặp
Bao lâu nên backup database một lần?
Với ứng dụng quản lý chi tiêu, backup đầy đủ mỗi đêm là đủ. Nếu dữ liệu thay đổi liên tục trong ngày, bổ sung WAL archiving để khôi phục tới từng thời điểm.
pg_dump có khóa database không?
Không. pg_dump chạy trong một transaction đọc nhất quán nên ứng dụng vẫn ghi bình thường, chỉ tốn thêm CPU và I/O trong lúc dump.
Backup media có cần mã hóa không?
Có, nếu media chứa dữ liệu nhạy cảm. Bật mã hóa phía server của bucket (SSE-S3 hoặc SSE-KMS) và chỉ cho tài khoản backup quyền ghi, không cho quyền xóa.
Restore lên máy khác cần lưu ý gì?
Kiểm tra phiên bản PostgreSQL đích phải bằng hoặc mới hơn bản nguồn, tạo đúng user và extension (ví dụ pg_trgm), rồi mới chạy file SQL.
Nguồn tham khảo
- PostgreSQL Documentation — pg_dump: https://www.postgresql.org/docs/current/app-pgdump.html
- PostgreSQL Documentation — Backup and Restore: https://www.postgresql.org/docs/current/backup.html
- rclone Documentation — rclone sync: https://rclone.org/commands/rclone_sync/
