برگشت به ساعت ۱۴:۲۹، یک دقیقه قبل از DELETE اشتباه
ساعت ۱۴:۳۰ کسی در psql نوشت DELETE FROM orders و WHERE را فراموش کرد. بکاپ شبانهی pg_dump یعنی از دست دادن ۱۴ ساعت سفارش. PITR (بازیابی به نقطهای از زمان) این را حل میکند: یک بکاپ فیزیکی پایه بهعلاوهی همهی فایلهای WAL بعد از آن، دیتابیس را به هر ثانیهی دلخواه برمیگرداند.
WAL چیست
هر تغییر قبل از نوشتن در فایلهای داده، در Write-Ahead Log (پوشهی pg_wal، قطعههای ۱۶ مگابایتی) ثبت میشود. پس از crash، پستگرس WAL را بازپخش میکند. اگر این قطعهها را جایی امن آرشیو کنیم، میتوانیم هر بازهای را دوباره پخش کنیم.
# postgresql.conf روی سرور اصلی (نیاز به restart)
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /mnt/wal_archive/%f && cp %p /mnt/wal_archive/%f'
archive_timeout = 300 # حداکثر ۵ دقیقه دادهی آرشیونشده
بکاپ پایه
sudo -u postgres pg_basebackup -D /backup/base_$(date +%F) \
-Ft -z -P -X stream -c fast --manifest-checksums=SHA256
# pg_verifybackup در 16 و 17 فقط بکاپ قالب plain (-Fp) را با manifest بررسی میکند
-X stream فایلهای WAL لازم برای سازگار بودن خود بکاپ را همزمان میگیرد؛ بدون آن، بکاپ بهتنهایی قابل بازگردانی نیست.
بازیابی به یک لحظه
sudo systemctl stop postgresql
sudo mv /var/lib/postgresql/16/main /var/lib/postgresql/16/main.broken
sudo -u postgres mkdir -m 700 /var/lib/postgresql/16/main
sudo -u postgres tar -xzf /backup/base_2026-03-10/base.tar.gz -C /var/lib/postgresql/16/main
sudo -u postgres tar -xzf /backup/base_2026-03-10/pg_wal.tar.gz -C /var/lib/postgresql/16/main/pg_wal
sudo -u postgres touch /var/lib/postgresql/16/main/recovery.signal
# postgresql.conf (یا postgresql.auto.conf)
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-03-10 14:29:00+03:30'
recovery_target_action = 'pause'
با pause سرور در لحظهی هدف میایستد و فقط خواندن را میپذیرد؛ داده را بررسی کنید و اگر درست بود SELECT pg_wal_replay_resume(); بزنید تا سرور promote شود. اگر هدف زودتر از لازم بود، زمان دیرتری بگذارید و سرور را دوباره راه بیندازید تا بازپخش ادامه یابد؛ اما اگر از لحظهی خطا گذشته باشید، راه برگشت فقط شروع دوباره از بکاپ پایه است.
ابزارهای حرفهای
در تولید، بهجای cp از ابزارهایی مثل pgBackRest، Barman یا WAL-G استفاده کنید: فشردهسازی، رمزنگاری، نگهداری دورهای و بکاپ افزایشی دارند و archive_command را امن انجام میدهند. نسخهی 17 خودش بکاپ افزایشی را با pg_basebackup --incremental و pg_combinebackup اضافه کرد (نیازمند summarize_wal = on).
نکتههایی که کمتر کسی میداند
- اگر archive_command خطا بدهد، پستگرس WAL را پاک نمیکند و pg_wal تا پر شدن دیسک رشد میکند.
pg_stat_archiverرا پایش کنید:failed_countوlast_failed_time. - بخش
test ! -fدر archive_command تصادفی نیست: جلوی بازنویسی یک قطعهی آرشیوشده با نسخهی دیگری (مثلاً از سرور دوم با همان مسیر) را میگیرد. - منطقهی زمانی recovery_target_time را صریح بنویسید (+03:30)؛ بدون آن، زمان بر اساس تنظیم timezone سرور تفسیر میشود که معمولاً UTC است و سه ساعت و نیم اشتباه میکنید.
- بکاپ فیزیکی کل کلاستر است: نمیتوان فقط یک دیتابیس یا یک جدول را با PITR برگرداند. راه معمول: بازیابی روی سرور موقت و برداشتن جدول با pg_dump.
- بکاپ فیزیکی فقط روی همان نسخهی اصلی (major) و همان معماری پردازنده بازمیگردد؛ برای انتقال بین نسخهها pg_dump یا pg_upgrade لازم است.