أتمتة اختبار PostgreSQL Backup قبل ما تحتاجه في كارثة
هتخرج من المقال ده بأوتوميشن بسيط يجاوب على سؤال أهم من "هل اتعمل backup؟": هل النسخة دي ينفع نرجّع منها الإنتاج فعلًا؟
مستوى القارئ: متوسط
المشكلة باختصار
الطريقة الشائعة بتفشل في نقطة قاتلة: فريق التشغيل بيتأكد إن ملف الـ backup اتولد، لكن لا يتأكد إن الملف قابل للاسترجاع. الملف ممكن يكون ناقص، أو معمول بإصدار غير مناسب، أو فيه schema بتفشل وقت restore. اللي بيحصل فعلاً إن المشكلة تظهر يوم الكارثة، وده أسوأ توقيت للاكتشاف.
الافتراض إن عندك PostgreSQL production صغير أو متوسط، أقل من 200GB، وبتستخدم pg_dump أو dump archive يومي. لو عندك 50K زائر يوميًا، توقف قاعدة البيانات ساعة واحدة ممكن يضيع طلبات ودفع ودعم عملاء. لذلك أفضل طريقة هنا مش زيادة عدد النسخ فقط، بل اختبار نسخة واحدة يوميًا على قاعدة مؤقتة.
الفكرة بمثال واضح
ركز في المثال ده. عندك مطعم بيسجّل كل الطلبات في دفتر. كل ليلة بتصور الدفتر وتحفظ الصورة. ده جيد، لكنه لا يثبت إن الصورة مقروءة. الاختبار الحقيقي إنك تفتح الصورة، تقرأ آخر 10 طلبات، وتتأكد إن أرقام اليوم متطابقة. في PostgreSQL، الصورة هي ملف .dump، والقراءة هي pg_restore على قاعدة مؤقتة، وفحص آخر الطلبات هو smoke query.
المفهوم بدقة: أوتوميشن التحقق من الـ backup يعمل restore معزول، ثم ينفذ فحوصات صغيرة لكنها ممثلة. مثال: عدد المستخدمين أكبر من صفر، جدول الطلبات موجود، آخر طلب خلال آخر 48 ساعة، واستعلام API مهم يرجع نتيجة. كده أنت لا تختبر التخزين فقط، بل تختبر قابلية الرجوع.
السكربت العملي
احفظ السكربت التالي باسم verify_pg_backup.sh. عدّل أسماء المتغيرات حسب بيئتك. السكربت ينشئ قاعدة مؤقتة، يسترجع آخر dump، ينفذ فحصين، ثم يحذف القاعدة في النهاية.
#!/usr/bin/env bash
set -euo pipefail
BACKUP_FILE="/backups/app-latest.dump"
TEMP_DB="restore_check_$(date +%Y%m%d_%H%M%S)"
PG_URL="postgresql://postgres:postgres@localhost:5432/postgres"
SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}"
started_at=$(date +%s)
created=0
cleanup() {
if [ "$created" = "1" ]; then
dropdb "$TEMP_DB" --if-exists
fi
}
trap cleanup EXIT
createdb "$TEMP_DB"
created=1
pg_restore --dbname="$TEMP_DB" --clean --if-exists --no-owner "$BACKUP_FILE"
users_count=$(psql "$TEMP_DB" -tAc "select count(*) from users;")
recent_orders=$(psql "$TEMP_DB" -tAc "select count(*) from orders where created_at >= now() - interval '48 hours';")
if [ "$users_count" -lt 1 ]; then
status="FAIL: users table is empty after restore"
elif [ "$recent_orders" -lt 1 ]; then
status="WARN: no recent orders in restored backup"
else
elapsed=$(( $(date +%s) - started_at ))
status="PASS: restore completed in ${elapsed}s, users=${users_count}, recent_orders=${recent_orders}"
fi
printf '%s\n' "$status"
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -sS -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"PostgreSQL backup verification: ${status}\"}" \
"$SLACK_WEBHOOK_URL" >/dev/null
fi
case "$status" in
PASS:*) exit 0 ;;
WARN:*) exit 2 ;;
*) exit 1 ;;
esacشغّله يوميًا عبر cron بعد انتهاء الـ backup بساعة. مثال الساعة 3:30 صباحًا:
30 3 * * * /opt/ops/verify_pg_backup.sh >> /var/log/backup-verify.log 2>&1الأرقام التي تهمك
في فريق صغير، فحص "الملف موجود" يديك ثقة شكلية. تقدير عملي: 35% ثقة فقط، لأنه لا يختبر schema ولا البيانات. بعد restore ناجح على قاعدة مؤقتة، الثقة تقفز تقريبًا إلى 78%. بعد smoke queries ممثلة، توصل إلى 90% أو أكثر. الرقم مش ضمان مطلق، لكنه يقلل مساحة المجهول بشكل واضح.
الـ trade-off هنا
بتكسب إنك تكتشف مشكلة الاسترجاع قبل يوم العطل. وتكسب سجل يومي واضح يثبت إن آخر نسخة قابلة للاستخدام. التكلفة: مساحة مؤقتة، وقت restore، وحمل بسيط على سيرفر الاختبار. لو الـ backup حجمه 20GB، ممكن الاختبار ياخد من 8 إلى 20 دقيقة حسب القرص. لذلك لا تشغّله على نفس production server لو الموارد ضيقة.
نقطة مهمة: استخدم قاعدة مؤقتة معزولة، ولا تعمل restore فوق staging مستخدم فعليًا من فريق التطوير. بدل ما تصلح مشكلة backup، ممكن تكسر بيئة يعتمد عليها الناس.
متى لا تستخدم هذه الطريقة
لا تستخدمها كما هي لو قاعدة البيانات ضخمة جدًا، مثل 2TB، لأن restore يومي كامل قد يكون مكلفًا. في الحالة دي اختبر عينة دورية، أو اعمل restore كامل أسبوعي، واستخدم WAL archiving وPITR للفحص الأكثر جدية. كذلك لا تستخدم webhook عام بدون حماية؛ رابط Slack webhook يعتبر سرًا ويجب حفظه في secret manager أو متغير بيئة آمن.
مصادر اعتمد عليها
- توثيق PostgreSQL الرسمي لأداة pg_dump.
- توثيق PostgreSQL الرسمي لأداة pg_restore.
- توثيق pg_isready لفحص جاهزية الاتصال.
- توثيق Slack Incoming Webhooks.
- مرجع صيغة crontab.
الخطوة التالية
افتح آخر backup عندك اليوم، وشغّل restore يدويًا على قاعدة مؤقتة مرة واحدة. لو نجح، حوّل نفس الخطوات إلى cron يومي، وخلي التقرير يروح لقناة تشغيل واضحة.