`pg_dump` rất hữu ích cho backup logic, nhưng khi cần khôi phục database về đúng thời điểm ngay trước một thao tác xóa nhầm, bạn cần Point-in-Time Recovery. PostgreSQL PITR kết hợp base backup với chuỗi WAL được archive liên tục để replay dữ liệu tới một mốc thời gian, LSN hoặc restore point xác định. Bài viết này hướng dẫn kiến trúc PITR, cấu hình `archive_mode`, kiểm tra archive, tạo base backup và quy trình recovery an toàn trên PostgreSQL hiện đại.
Một bản pg_dump lúc 02:00 không giúp bạn quay lại trạng thái 10:37 nếu người dùng xóa nhầm dữ liệu lúc 10:38 và backup tiếp theo chưa chạy. Đây là bài toán mà Point-in-Time Recovery (PITR) giải quyết.
PITR của PostgreSQL dựa trên hai thành phần:
- Base backup — ảnh chụp vật lý nhất quán của cluster;
- WAL archive — các WAL segment được lưu liên tục sau đó.
Khi cần khôi phục, PostgreSQL restore base backup rồi replay WAL cho tới đúng thời điểm hoặc điểm khôi phục mà bạn chọn.
Nếu mục tiêu của bạn chỉ là export một database hoặc vài bảng, pg_dump vẫn đơn giản hơn. PITR phù hợp khi bạn cần RPO thấp và khả năng quay lại một thời điểm cụ thể.
Nếu PostgreSQL hiện đang chậm, đừng nhầm backup với tuning; xem thêm bài PostgreSQL chậm trên VPS.
PITR hoạt động thế nào?
PostgreSQL ghi mọi thay đổi cần cho crash recovery vào WAL — Write-Ahead Log.
Khi bật archive:
PostgreSQL
|
| WAL segment hoàn tất
v
WAL archive storage
Một chu kỳ backup có dạng:
Base backup lúc 00:00
+ WAL 00:00 → 10:37
= có thể recovery tới 10:37
Nếu thiếu WAL giữa chuỗi, recovery sẽ không thể đi qua khoảng bị thiếu đó.
PITR khác pg_dump thế nào?
| Tiêu chí | pg_dump | PITR |
|---|---|---|
| Kiểu backup | Logic | Physical + WAL |
| Khôi phục từng bảng | Dễ | Không phải mục tiêu chính |
| Khôi phục đúng thời điểm | Không | Có |
| Phù hợp DB lớn | Có giới hạn thực tế | Thường phù hợp hơn |
| Yêu cầu WAL archive | Không | Có |
| Restore sang major version khác | Có thể | Không theo cách physical backup trực tiếp |
Hai phương pháp có thể cùng tồn tại.
Điều kiện để bật PITR
Theo tài liệu PostgreSQL hiện hành, continuous archiving yêu cầu:
wal_level = replica
archive_mode = on
và một trong:
archive_command = '...'
hoặc archive_library.
wal_level = replica là mặc định phổ biến trên PostgreSQL hiện đại, nhưng hãy kiểm tra thực tế:
SHOW wal_level;
SHOW archive_mode;
SHOW archive_command;
Chuẩn bị nơi lưu WAL
Trong lab, có thể archive vào disk mount riêng:
sudo mkdir -p /backup/postgresql/wal
sudo chown postgres:postgres /backup/postgresql/wal
sudo chmod 700 /backup/postgresql/wal
Production tốt hơn nên có bản sao off-server hoặc object/storage riêng để việc mất toàn bộ VPS không kéo theo mất cả WAL archive.
Không lưu bản backup duy nhất ngay trên cùng filesystem với database.
Cấu hình archive_command
Mở postgresql.conf. Tìm đường dẫn chính xác:
SHOW config_file;
Ví dụ đơn giản:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /backup/postgresql/wal/%f && cp %p /backup/postgresql/wal/%f'
Trong archive_command:
%p= đường dẫn WAL file nguồn;%f= tên WAL file.
Ví dụ trên chỉ phù hợp để hiểu cơ chế. Với production, nên dùng script/tool backup có kiểm tra checksum, retry, off-site copy và monitoring.
Sau thay đổi archive_mode, cần restart PostgreSQL:
sudo systemctl restart postgresql
Kiểm tra archiver
Trong PostgreSQL:
SELECT * FROM pg_stat_archiver;
Quan tâm:
archived_count;failed_count;last_archived_wal;last_failed_wal;- thời điểm archive gần nhất.
Ép switch WAL để kiểm tra:
SELECT pg_switch_wal();
Sau đó:
ls -lh /backup/postgresql/wal
Nếu failed_count tăng, đừng tạo base backup rồi nghĩ PITR đã an toàn. Hãy sửa archive pipeline trước.
Vì sao WAL archive lỗi có thể làm đầy disk?
PostgreSQL không thể tùy ý xóa WAL segment chưa archive thành công khi archive mode yêu cầu giữ chúng.
Nếu destination mất kết nối hoặc script archive fail kéo dài, pg_wal có thể tăng mạnh.
Do đó cần alert cho:
failed_count;- thời gian kể từ lần archive thành công cuối;
- dung lượng
pg_wal; - disk usage.
Nếu bạn đã dùng Prometheus, có thể tích hợp cảnh báo theo bài Cài Alertmanager cho Prometheus.
Tạo base backup bằng pg_basebackup
Tạo thư mục:
sudo mkdir -p /backup/postgresql/base
sudo chown postgres:postgres /backup/postgresql/base
Ví dụ:
sudo -u postgres pg_basebackup \
-D /backup/postgresql/base/base-$(date +%F-%H%M) \
-Fp \
-Xs \
-P
Ý nghĩa:
-D: thư mục đích;-Fp: plain format;-Xs: stream WAL cần thiết trong lúc backup;-P: hiển thị progress.
Trước production, kiểm tra version pg_basebackup --help vì option có thể thay đổi giữa major release.
Base backup và WAL phải đi cùng nhau
Một base backup đơn lẻ chỉ đưa bạn về thời điểm backup.
Muốn PITR tới thời điểm sau đó, cần toàn bộ WAL cần thiết kể từ base backup tới recovery target.
Vì vậy retention phải được thiết kế theo chu kỳ base backup.
Ví dụ:
- base backup mỗi Chủ nhật;
- giữ WAL đủ để phục hồi ít nhất 7–14 ngày;
- chỉ xóa WAL archive khi chắc chắn không còn base backup nào phụ thuộc vào chúng.
Không xóa WAL archive bằng cron find -mtime tùy tiện nếu chưa mô hình hóa dependency.
Tạo restore point có tên
Trước migration lớn:
SELECT pg_create_restore_point('before_orders_migration');
Sau đó nếu cần PITR, có thể recovery tới restore point thay vì phải nhớ timestamp chính xác.
Restore point hữu ích trước:
- migration schema;
- import dữ liệu lớn;
- release có thay đổi DB;
- batch update quan trọng.
Nó không thay base backup và WAL archive.
Quy trình khôi phục an toàn
PITR không nên test lần đầu ngay trên production đang hỏng.
Quy trình tốt hơn:
- tạo VPS/instance recovery riêng;
- restore base backup vào đó;
- cấu hình
restore_command; - đặt recovery target;
- start PostgreSQL;
- xác minh dữ liệu;
- sau đó mới quyết định cutover.
Dừng PostgreSQL trên máy recovery
Ví dụ:
sudo systemctl stop postgresql
Xác định data directory:
SHOW data_directory;
Cảnh báo: thao tác physical restore sẽ thay toàn bộ data directory. Không chạy lệnh xóa/copy trên production khi chưa có backup và chưa xác định đúng đường dẫn.
Restore base backup
Ví dụ conceptual:
sudo rsync -aHAX /backup/postgresql/base/base-2026-10-06-0000/ /var/lib/postgresql/18/main/
Sau đó chỉnh owner:
sudo chown -R postgres:postgres /var/lib/postgresql/18/main
Đường dẫn version/distro có thể khác.
Cấu hình restore_command
Từ PostgreSQL 12 trở lên, recovery.conf cũ đã bị loại bỏ. Recovery parameters nằm trong cấu hình PostgreSQL thông thường.
Ví dụ:
restore_command = 'cp /backup/postgresql/wal/%f %p'
recovery_target_time = '2026-10-06 10:37:00+07'
recovery_target_action = 'promote'
Tạo file signal trong data directory:
sudo -u postgres touch /var/lib/postgresql/18/main/recovery.signal
Sau đó start:
sudo systemctl start postgresql
PostgreSQL sẽ restore WAL và dừng/promote theo target đã định.
Recovery target có thể là gì?
PostgreSQL hỗ trợ nhiều loại target, trong đó phổ biến:
Theo thời gian
recovery_target_time = '2026-10-06 10:37:00+07'
Theo restore point
recovery_target_name = 'before_orders_migration'
Theo LSN
recovery_target_lsn = '0/1234ABCD'
Chỉ được cấu hình một loại target chính tại một thời điểm.
recovery_target_inclusive
Mặc định target thường inclusive.
Nếu cần dừng trước transaction đúng tại timestamp/LSN:
recovery_target_inclusive = off
Đây là chi tiết rất quan trọng nếu bạn đang cố tránh một transaction phá dữ liệu xảy ra chính xác ở target.
Kiểm tra log recovery
Theo dõi:
sudo journalctl -u postgresql -f
hoặc PostgreSQL log path thực tế.
Bạn muốn thấy tiến trình restore WAL và target được đạt tới.
Nếu thiếu một WAL segment, recovery có thể dừng trước target.
Sau khi recovery thành công
Xác minh dữ liệu trước:
SELECT now();
SELECT count(*) FROM important_table;
Kiểm tra transaction gần thời điểm sự cố bằng dữ liệu business phù hợp.
Sau PITR, cluster đi trên một timeline mới. Nếu bạn tiếp tục backup chuỗi mới, cần quản lý WAL/timeline history đúng cách.
Không recovery trực tiếp đè production khi chưa xác minh
Một quy trình an toàn hơn:
- restore sang server mới;
- kiểm tra application read-only;
- so sánh dữ liệu;
- freeze write production nếu cần;
- cutover DNS/application;
- giữ server cũ trong một khoảng rollback hợp lý.
Điều này giảm rủi ro “khôi phục xong nhưng target sai”.
Dùng tool backup chuyên dụng
Với production, các tool như pgBackRest, Barman hoặc WAL-G giúp quản lý:
- base backup;
- WAL archive;
- retention;
- compression;
- object storage;
- restore workflow;
- verification.
Bài này dùng công cụ PostgreSQL native để giải thích cơ chế. Khi database lớn, nên cân nhắc tool chuyên dụng thay vì tự viết nhiều shell script.
PITR không thay replication
Streaming replica giúp availability và read scaling.
Nhưng nếu user chạy:
DELETE FROM orders;
transaction có thể replicate sang standby rất nhanh. Replica không phải backup chống lỗi logic.
PITR giúp quay về trước thời điểm lỗi đó.
PITR không thay pg_dump
PITR phục hồi toàn cluster tới một thời điểm.
Nếu chỉ cần restore một table bị xóa nhầm, đôi khi quy trình tốt là:
- PITR sang recovery server;
pg_dumptable cần lấy;- import table/dữ liệu đó về production.
Như vậy không phải rollback toàn hệ thống.
Monitoring cần có
Theo dõi:
- lần base backup thành công cuối;
- WAL archive success/fail;
- độ trễ archive;
- dung lượng archive storage;
pg_walgrowth;- restore test gần nhất.
Backup không được restore test thì vẫn là rủi ro chưa được kiểm chứng.
Sai lầm thường gặp
Bật archive_mode nhưng không kiểm tra pg_stat_archiver
Archive command có thể fail âm thầm trong thời gian dài.
Lưu WAL cùng disk với database
Mất VPS/disk có thể mất cả dữ liệu và backup.
Chỉ giữ WAL 1 ngày nhưng base backup mỗi tuần
Bạn mất chuỗi cần cho PITR các ngày cũ.
Dùng recovery.conf trên PostgreSQL mới
PostgreSQL 12+ không còn dùng file này.
Chưa từng test restore
Đến sự cố mới phát hiện thiếu WAL hoặc script restore sai.
Checklist PITR
-
wal_level=replicahoặc cao hơn. -
archive_mode=on. -
archive_commandđược kiểm tra. -
pg_stat_archiver.failed_countkhông tăng. - Có base backup định kỳ.
- Retention WAL khớp retention base backup.
- WAL có bản sao off-server.
- Có restore point trước thay đổi lớn nếu phù hợp.
- Đã test
recovery_target_timetrên server riêng. - Có monitoring disk và archive lag.
FAQ
PITR có cần WAL archive không?
Có. Base backup chỉ là điểm bắt đầu; WAL archive cung cấp chuỗi thay đổi để replay tới target.
Có thể recovery tới đúng trước lệnh DELETE không?
Có, nếu WAL cần thiết vẫn còn và bạn xác định được timestamp/restore point/LSN phù hợp.
PostgreSQL 12+ có dùng recovery.conf không?
Không. Recovery settings nằm trong cấu hình PostgreSQL và dùng recovery.signal.
PITR có restore riêng một table không?
Không trực tiếp. Có thể PITR sang server tạm rồi pg_dump table cần lấy.
Bao lâu nên test restore?
Tùy mức quan trọng, nhưng production nên có lịch định kỳ thay vì chờ sự cố thật. Hệ thống càng quan trọng càng cần test thường xuyên.
Kết luận
PostgreSQL PITR là lớp bảo vệ quan trọng khi bạn cần quay lại một thời điểm cụ thể thay vì chỉ restore bản backup gần nhất. Kiến trúc đúng gồm base backup, WAL archive liên tục, retention hợp lý, monitoring và restore test.
Hãy triển khai PITR trước khi sự cố xảy ra, không phải sau khi dữ liệu đã bị xóa.
Nếu database của bạn cần VPS riêng cho production, standby hoặc recovery testing, có thể tham khảo các dịch vụ VPS tại HUONG CLOUD và chọn tài nguyên dựa trên dung lượng database, WAL rate và RTO/RPO thực tế.
Nguồn tham khảo
- PostgreSQL 18 — Backup and Restore: https://www.postgresql.org/docs/current/backup.html
- PostgreSQL — WAL configuration and recovery targets: https://www.postgresql.org/docs/current/runtime-config-wal.html
- PostgreSQL — Continuous Archiving and PITR: https://www.postgresql.org/docs/current/continuous-archiving.html
- PostgreSQL — recovery.conf changes since PostgreSQL 12: https://www.postgresql.org/docs/current/recovery-config.html
Kết luận
Nếu chưa chắc cấu hình hoặc loại dịch vụ nào phù hợp, hãy gửi nhu cầu thực tế để đội ngũ hỗ trợ tư vấn trước khi mua.
Chưa biết nên chọn gói nào?
Xem bảng giá VPS hoặc liên hệ đội ngũ hỗ trợ để chọn cấu hình phù hợp.
Xem bảng giá VPS →