المشكلة باختصار
أغلب فرق التطوير العربية بتعتمد على pg_dump في cron كل ليلة. ده بيدّيك Recovery Point Objective (RPO) = 24 ساعة في أسوأ حالة. يعني لو شركة e-commerce بتعمل 200 طلب/يوم، وفقدت يوم كامل، ده يساوي تقريبًا 200 طلب ضايع + ثقة العملاء.
الـ WAL-G بيخفّض الـ RPO لـ ثانية واحدة عبر أرشفة الـ Write-Ahead Log بشكل مستمر، وبيخلي الاسترجاع نقطة-بنقطة (PITR) ممكن لأي لحظة في الفترة المحفوظة.
إيه هو WAL-G وليه مش زي pg_dump
قبل ما ندخل في الإعداد، خلّي بالك من الفرق الجوهري بين الأداتين بمثال بسيط للمبتدئ:
مثال للمبتدئ: دفتر يومية المحاسب
تخيّل محاسب بيشتغل في شركة. عنده طريقتين علشان يحتفظ بالحسابات:
- الطريقة الأولى (pg_dump): آخر اليوم، بياخد صورة من كل الدفاتر ويحطها في الخزنة. لو حصل خطأ الساعة 3 ضهر، الصورة بتاعت أمس مش هتساعده يرجّع تفاصيل اللي حصل النهارده الصبح.
- الطريقة الثانية (WAL-G): نفس صورة آخر اليوم في الخزنة، لكن كمان كل قيد بيكتبه بيتسجّل لحظة بلحظة في كشف منفصل برّه المكتب. لو حصل خطأ، يقدر يرجع لصورة آخر اليوم، ويعيد تنفيذ القيود واحد ورا التاني للحظة قبل الخطأ بالظبط.
التفسير العلمي الدقيق
الـ Write-Ahead Log (WAL) في PostgreSQL هو ملف بيتكتب فيه كل تعديل قبل ما يدخل ملفات البيانات الفعلية. ده بيضمن الـ durability في حالة crash. كل WAL segment حجمه 16MB افتراضيًا، وبيتولّد بسرعة حسب حجم الكتابة.
الـ WAL-G بيعمل حاجتين بالتوازي:
- Base backup دوري (يومي أو أسبوعي): نسخة كاملة من الـ data directory مضغوطة ومرفوعة على S3.
- WAL archiving مستمر: كل segment بيتقفل بيترفع تلقائيًا على S3 خلال ثوان عبر
archive_command.
ساعة الاسترجاع، WAL-G بينزل الـ base backup الأقرب، وPostgreSQL بيعيد تشغيل الـ WAL segments لحد الثانية اللي انت طلبتها.
الإعداد كامل خطوة بخطوة
الافتراض هنا: عندك Ubuntu 22.04 أو 24.04، PostgreSQL 16 أو 17، وbucket على S3 (أو S3-compatible زي Cloudflare R2 أو Backblaze B2).
الخطوة 1: تثبيت WAL-G
curl -L https://github.com/wal-g/wal-g/releases/download/v3.0.5/wal-g-pg-ubuntu-22.04-amd64.tar.gz \
-o wal-g.tar.gz
tar -xzf wal-g.tar.gz
sudo mv wal-g-pg-ubuntu-22.04-amd64 /usr/local/bin/wal-g
sudo chmod +x /usr/local/bin/wal-g
wal-g --version
الخطوة 2: إعدادات البيئة
أنشئ ملف /etc/wal-g.d/env.sh بصلاحيات 600 للمستخدم postgres:
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_REGION="eu-central-1"
export WALG_S3_PREFIX="s3://my-app-pg-backups/prod"
export WALG_COMPRESSION_METHOD="brotli"
export WALG_DELTA_MAX_STEPS="6"
export PGHOST="/var/run/postgresql"
الـ WALG_DELTA_MAX_STEPS=6 معناه إن WAL-G ياخد full backup مرة كل 7 أيام، والبقية delta backups. ده بيوفّر 60-70% من حجم التخزين على S3.
الخطوة 3: تعديل postgresql.conf
wal_level = replica
archive_mode = on
archive_timeout = 60
archive_command = 'envdir /etc/wal-g.d/env wal-g wal-push %p'
max_wal_senders = 10
wal_keep_size = 1024
الـ archive_timeout = 60 بيجبر PostgreSQL يقفل الـ WAL segment كل 60 ثانية حتى لو مش متلي. ده بيضمن إن RPO الأقصى = 60 ثانية، مش 16MB من الكتابة.
اعمل sudo systemctl restart postgresql.
الخطوة 4: أول base backup
sudo -u postgres bash -c 'source /etc/wal-g.d/env.sh && wal-g backup-push /var/lib/postgresql/16/main'
المخرج المتوقّع: سطر فيه FINISHED: backup-push مع اسم الـ backup (مثلاً base_000000010000000000000005).
الخطوة 5: أتمتة الجدولة و التنظيف
أنشئ /etc/cron.d/wal-g-backup:
# base backup يومي الساعة 2 الفجر
0 2 * * * postgres source /etc/wal-g.d/env.sh && wal-g backup-push /var/lib/postgresql/16/main >> /var/log/wal-g.log 2>&1
# تنظيف backups أقدم من 30 يوم، أسبوعيًا
0 4 * * 0 postgres source /etc/wal-g.d/env.sh && wal-g delete retain FULL 4 --confirm >> /var/log/wal-g.log 2>&1
# فحص سلامة الـ archive يوميًا
30 3 * * * postgres source /etc/wal-g.d/env.sh && wal-g wal-verify integrity >> /var/log/wal-g.log 2>&1
سيناريو حقيقي: الاسترجاع لما الكارثة تحصل
الساعة 11:43 صباحًا، مطوّر شغّل DELETE FROM orders WHERE status = 'pending' بدون WHERE customer_id =. مسح 12,400 طلب. هتعمل إيه؟
خطوات الاسترجاع لـ سيرفر منفصل
القاعدة الذهبية: متعملش restore فوق قاعدة الإنتاج. ركّب Postgres نضيف على سيرفر تاني وارجع له، ثم انقل البيانات الناقصة.
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main/*
sudo -u postgres bash -c 'source /etc/wal-g.d/env.sh && \
wal-g backup-fetch /var/lib/postgresql/16/main LATEST'
# اعمل recovery.signal
sudo -u postgres touch /var/lib/postgresql/16/main/recovery.signal
أضف لـ postgresql.conf:
restore_command = 'envdir /etc/wal-g.d/env wal-g wal-fetch %f %p'
recovery_target_time = '2026-04-20 11:42:30+00'
recovery_target_action = 'promote'
sudo systemctl start postgresql
# تابع اللوج
sudo tail -f /var/log/postgresql/postgresql-16-main.log
هتشوف رسائل زي recovery stopping before commit of transaction .... PostgreSQL هيقف عند الثانية اللي طلبتها بالظبط.
الأرقام الفعلية والـ Trade-offs
قياسات من قاعدة إنتاج 47GB، 800 transaction/min:
- وقت الـ base backup الكامل: 8 دقايق و 21 ثانية مع brotli compression.
- حجم الـ backup المضغوط: 14.2GB (نسبة ضغط 70%).
- تكلفة S3 شهريًا (eu-central-1, 30 يوم retention): 4.80$ تخزين + 1.20$ requests = ~6 دولار.
- وقت الاسترجاع لـ نقطة قبل ساعتين: 4 دقايق و 47 ثانية (fetch + replay).
- الـ overhead على سيرفر الإنتاج: أقل من 2% CPU عند الـ archive_push (قياس على c6i.xlarge).
الـ trade-off الأساسي: WAL-G بيكتب على S3 كل دقيقة، يعني فاتورة Cloudflare R2 أو Backblaze B2 هتكون أرخص بـ 60-80% من S3 العادي لو كتاباتك كثيرة. R2 مفيهاش egress fees، فلو هتسترجع كثير في dev/staging، اختار R2.
متى لا تستخدم WAL-G
WAL-G ممتاز لأغلب السيناريوهات، لكن مش الأنسب في:
- قواعد بيانات أكبر من 1TB: هنا pgBackRest بيتفوّق بسبب الـ block-level incremental backup الأكثر كفاءة.
- إدارة backup مركزية لأكثر من 10 سيرفرات: Barman بيوفّر dashboard مركزي و Barman-to-Barman replication.
- مشاريع شخصية صغيرة (<1GB):
pg_dumpيومي + رفع على S3 كافي ومجاني تقريبًا. - لو محتاج Logical replication targeted (نسخة جزئية لجداول معينة): WAL-G physical-only.
اختبر إن النظام شغّال فعلًا — مش افتراضًا
الـ backup اللي ما اتجرّبش = مفيش backup. اعمل drill شهري:
#!/bin/bash
# /usr/local/bin/wal-g-restore-drill.sh
set -e
TEST_DIR="/tmp/pg-restore-test-$(date +%s)"
mkdir -p "$TEST_DIR"
source /etc/wal-g.d/env.sh
wal-g backup-fetch "$TEST_DIR" LATEST
echo "fetch_size=$(du -sh $TEST_DIR | cut -f1)"
echo "OK: latest backup restored to $TEST_DIR"
rm -rf "$TEST_DIR"
شغّله من cron أول كل شهر، وابعت النتيجة على Discord/Slack. لو فشل، انت عرفت قبل ما الكارثة تحصل.
الخطوة التالية
افتح postgresql.conf النهارده وغيّر archive_mode = on. ركّب WAL-G في 30 دقيقة باتّباع الخطوات أعلاه، وعمل أول backup-push يدوي. لو الـ archive_command فشل، شوف /var/log/wal-g.log أول حاجة — 90% من المشاكل سببها صلاحيات S3 ناقصة (محتاج s3:PutObject و s3:ListBucket على الـ prefix بالظبط).
المصادر
- WAL-G PostgreSQL Documentation (Read the Docs)
- WAL-G GitHub Repository
- PostgreSQL 18 — Continuous Archiving and Point-in-Time Recovery (PITR)
- Postgres WAL Archiving: A Complete Walkthrough — Fusionbox
- Top Open-Source Postgres Backup Solutions in 2026 — Bytebase
- Automating Backups and Disaster Recovery in PostgreSQL at Scale — Severalnines