هذا المقال للمستوى المبتدئ. هتطلع منه بسكربت Backup يومي لـ PostgreSQL على S3 في 40 سطر، مع خطة استرجاع جاهزة تشتغل في أقل من 4 دقايق على DB حجمها 8GB.
Backup يومي لـ PostgreSQL على S3 — السكربت اللي بينقذك يوم ما السيرفر يقع
لو عندك DB إنتاج من غير backup أوتوماتيكي في موقع منفصل، أنت ماشي على حبل. يوم ما القرص يفسد أو حد ينفّذ DROP TABLE بالغلط، الخسارة مش بس بيانات، الخسارة وقت توقف وثقة عميل. الحل في 40 سطر bash و 5 دقايق إعداد.
المشكلة باختصار
كتير من الفرق الصغيرة بتعتمد على snapshot من مزوّد الاستضافة وبس. ده backup مش استراتيجية. Snapshot على نفس المزوّد بيموت لو الحساب اتقفل أو منطقة الـ availability zone وقعت ساعة كاملة. الطريقة دي بتفشل في الحالة اللي محتاج فيها الـ backup فعلًا — اللحظة اللي الكارثة فيها واصلة لكل حاجة في نفس الحساب.
تخيّل الموضوع كده — مثال للمبتدئ
تخيّل إنك بتمسك دفتر حسابات شركة. كل يوم بتاخد صورة من الدفتر وتحطها في خزنة في بنك تاني في حي تاني. لو حصل حريق في مكتبك، الدفتر اللي في البنك بيرجّعك تشتغل بكرة الصبح. لكن لو حطيت الصورة في دُرج جنب الدفتر الأصلي، النار هتاكلهم الاتنين.
الـ snapshot من مزوّد الاستضافة = الدُرج جنب الدفتر. الـ backup على S3 في حساب AWS مختلف = البنك في الحي التاني.
التعريف الدقيق — الفرق بين Logical و Physical Backup
Logical backup (زي اللي pg_dump بيعمله): بيقرا الجداول صف صف ويولّد ملف SQL فيه أوامر CREATE TABLE و INSERT. مرن جدًا، بيشتغل بين إصدارات مختلفة من PostgreSQL، وحجم الملف صغير بعد الضغط.
Physical backup (زي pg_basebackup): بيناخد نسخة بايت-بـ-بايت من ملفات الـ data directory. أسرع في الاسترجاع، لكنه مرتبط بإصدار PostgreSQL ومعمارية السيرفر.
الافتراض هنا: الـ DB بتاعتك أقل من 50GB، وبتستحمل قفل قراءة لمدة دقايق. فوق كده، اقرا قسم "متى لا تستخدم" في الآخر.
الأدوات اللي محتاجها
- pg_dump: أداة رسمية شغّالة مع PostgreSQL منذ 1996، موثّقة في توثيق PostgreSQL الرسمي.
- aws-cli v2: بترفع الملف على S3 بـ multipart upload أوتوماتيكي للملفات الكبيرة.
- systemd timer: بديل أنظف من cron في الجدولة، logs مرتبة في
journalctl. - bucket S3 في حساب AWS مختلف: ده الجزء المهم — مش نفس الحساب اللي السيرفر فيه.
السكربت في 40 سطر
#!/usr/bin/env bash
set -euo pipefail
DB_NAME="${DB_NAME:-app_production}"
DB_USER="${DB_USER:-postgres}"
S3_BUCKET="${S3_BUCKET:-my-db-backups}"
RETENTION_DAYS="${RETENTION_DAYS:-30}"
TIMESTAMP=$(date -u +%Y%m%d_%H%M%S)
DUMP_FILE="/tmp/${DB_NAME}_${TIMESTAMP}.sql.gz"
S3_KEY="postgres/${DB_NAME}/${TIMESTAMP}.sql.gz"
echo "[$(date -Iseconds)] Starting backup of ${DB_NAME}"
# 1) Dump مع ضغط مباشر
pg_dump --no-owner --no-acl \
-U "${DB_USER}" -h localhost "${DB_NAME}" \
| gzip -9 > "${DUMP_FILE}"
# 2) فحص حجم بسيط — لو طلع أقل من 1KB يبقى فشل صامت
SIZE=$(stat -c%s "${DUMP_FILE}")
if [ "${SIZE}" -lt 1024 ]; then
echo "ERROR: dump too small (${SIZE} bytes)" >&2
exit 1
fi
# 3) رفع على S3 بـ Standard-IA لتوفير 45% من تكلفة التخزين
aws s3 cp "${DUMP_FILE}" "s3://${S3_BUCKET}/${S3_KEY}" \
--storage-class STANDARD_IA
rm -f "${DUMP_FILE}"
# 4) مسح أي backup أقدم من RETENTION_DAYS
CUTOFF=$(date -u -d "-${RETENTION_DAYS} days" +%Y%m%d)
aws s3 ls "s3://${S3_BUCKET}/postgres/${DB_NAME}/" \
| awk -v d="${CUTOFF}" '$4 ~ /sql.gz$/ && substr($4,1,8) < d {print $4}' \
| xargs -r -I{} aws s3 rm "s3://${S3_BUCKET}/postgres/${DB_NAME}/{}"
echo "[$(date -Iseconds)] Backup OK: ${S3_KEY} (${SIZE} bytes)"
السكربت ده بيعمل 4 حاجات بالظبط: dump مضغوط، فحص حجم بسيط (لو طلع 50 بايت معناه pg_dump فشل بصمت)، رفع على S3 بـ class أرخص، ومسح أي ملف أقدم من 30 يوم.
جدوله بـ systemd timer
cron شغّال لكن بيخفي الأخطاء بصمت. systemd بيكتب logs مرتبة في journalctl وبيعطيك RandomizedDelaySec علشان متبقاش كل السيرفرات بتاعتك بتعمل backup في نفس اللحظة وتكسر حدود AWS API.
# /etc/systemd/system/pg-backup.service
[Unit]
Description=PostgreSQL daily backup to S3
[Service]
Type=oneshot
EnvironmentFile=/etc/pg-backup.env
ExecStart=/usr/local/bin/pg_backup.sh
User=postgres
# /etc/systemd/system/pg-backup.timer
[Unit]
Description=Run pg-backup daily at 03:15 UTC
[Timer]
OnCalendar=*-*-* 03:15:00
RandomizedDelaySec=15min
Persistent=true
[Install]
WantedBy=timers.target
فعّله بأمرين:
sudo systemctl daemon-reload
sudo systemctl enable --now pg-backup.timerالجزء اللي 70% من الفرق بتنساه — استرجاع مُختبر
Backup من غير اختبار استرجاع = تخمين. كل أول الشهر، شغّل السكربت ده على سيرفر staging وقيس الزمن:
aws s3 cp \
s3://my-db-backups/postgres/app_production/20260507_031500.sql.gz - \
| gunzip \
| psql -U postgres -d staging_restoreعلى DB حجمها 8GB، استرجاع كامل بياخد حوالي 3 دقايق و 40 ثانية على شبكة 100 Mbps في AWS نفسها. لو طلعلك أكتر من 10 دقايق، فيه مشكلة في إعادة بناء الـ indexes أو bandwidth — لازم تعرفها قبل ما تحتاجها وقت الكارثة، مش وقتها.
الأرقام الفعلية على workload صغير
- DB حجمها 8GB → ملف
.sql.gzبحجم 1.2GB (نسبة ضغط 85% بسبب تكرار النصوص في الجداول). - زمن
pg_dump+ رفع S3: 4 دقايق و 12 ثانية على سيرفرt3.medium. - تكلفة شهرية على S3 Standard-IA: 30 ملف × 1.2GB × $0.0125/GB = $0.45 شهريًا.
- تكلفة استرجاع كامل (لو احتجته): $0.01/GB × 1.2GB = $0.012، يعني تقريبًا مجاني.
Trade-offs لازم تعرفها
بتكسب: نسخة آمنة في موقع مختلف، استرجاع متوقّع زمنه معروف، تكلفة بسيطة جدًا، وملف SQL إنساني تقدر تفتحه وتشوف بياناتك.
بتخسر: pg_dump بياخد قفل قراءة طويل (ACCESS SHARE) على الجداول الكبيرة، ممكن يأثر على query latency لمدة 2-5 دقايق وقت تشغيله. كمان وقت الاسترجاع طويل بالمقارنة مع physical backup. الافتراض إنك مرتاح إن RPO = 24 ساعة (يعني ممكن تخسر بيانات يوم كامل في أسوأ سيناريو).
متى لا تستخدم هذه الطريقة
الطريقة دي بتفشل في 3 حالات بالظبط:
- DB حجمها فوق 100GB:
pg_dumpهياخد ساعتين والاسترجاع ساعة. هنا انتقل لـ WAL archiving +pg_basebackupأو حل managed زي AWS RDS automated backups. - RPO المطلوب أقل من 24 ساعة: لو الخسارة المسموح بيها أقل من يوم بيانات، daily backup مش كافي — محتاج continuous archiving بـ WAL.
- محتاج Point-In-Time Recovery: لو محتاج ترجع للحظة محددة (مثلاً قبل الـ
DROP TABLEالغلط بـ 10 دقايق)، dump يومي مش هيخدمك. محتاج WAL archiving.
الخطوة التالية
افتح terminal، انسخ السكربت، شغّله مرة يدويًا (./pg_backup.sh) وأكّد إن الملف ظهر في S3 وحجمه منطقي مقارنة بحجم الـ DB. لو طلعت الأرقام مظبوطة، فعّل الـ timer. وحط alert على CloudWatch (أو Healthchecks.io المجاني) لو الـ object الجديد ما ظهرش لمدة 25 ساعة — ده الـ "dead man's switch" اللي بيمنعك تكتشف إن الـ backup واقف بعد شهرين.
المصادر
- توثيق
pg_dumpالرسمي — postgresql.org/docs/current/app-pgdump.html - PostgreSQL Backup and Restore — postgresql.org/docs/current/backup.html
- AWS S3 Storage Classes Pricing — aws.amazon.com/s3/storage-classes
- systemd.timer manpage — freedesktop.org/software/systemd/man/systemd.timer
- AWS CLI S3 Reference — docs.aws.amazon.com/cli/latest/reference/s3