البرمجة متوسط 9 دقيقة

كيفية أتمتة النسخ الاحتياطي لقاعدة بيانات MySQL باستخدام Cron

النسخ الاحتياطي اليدوي يفشل في نهاية المطاف. مهمة cron لـ mysqldump تعمل الساعة 2 صباحاً مضغوطة، محتفظاً بها 7 أيام، منسوخة خارج الخادم — لا تفشل. هذا الدليل يبني تلك البيئة بالضبط في أقل من ساعة، ويغطي الخطوة التي تتجاهلها معظم الدروس: اختبار الاستعادة.

الخطوات

  1. 1

    أنشئ مجلد النسخ الاحتياطي

    احفظ النسخ الاحتياطية في مكان ليس جذر الويب. اقيّده حتى يقرأه root فقط.

    bash
    sudo mkdir -p /home/backups
    sudo chmod 700 /home/backups
    # الملفات التي تُنشأ بداخله ترث قيود الوصول المحدودة
  2. 2

    احفظ بيانات الاعتماد بأمان في ~/.my.cnf

    تمرير كلمة المرور في سطر الأوامر يضعها في قائمة العمليات — قابلة للقراءة من أي مستخدم بـ ps aux. احفظها في ~/.my.cnf عوضاً عن ذلك. في MariaDB مع مصادقة unix_socket يمكنك تخطي كلمة المرور كلياً.

    bash
    # أنشئ /root/.my.cnf (شغّل كـ root أو بـ sudo su)
    cat > /root/.my.cnf << "EOF"
    [mysqldump]
    user=root
    password=your_db_password_here
    EOF
    
    # قيّد الصلاحيات — root وحده يقرأ هذا الملف
    chmod 600 /root/.my.cnf
    
    # في MariaDB مع مصادقة unix_socket، يمكن أن يكون الملف:
    # [mysqldump]
    # user=root
    # (بدون سطر كلمة المرور — MariaDB تصادق عبر مستخدم النظام)
  3. 3

    اكتب سكريبت النسخ الاحتياطي

    --single-transaction هو الخيار الحاسم — يلفّ جداول InnoDB في transaction حتى تكون النسخة متسقة دون قفل أي جداول. --quick يدفق الصفوف واحدة تلو الأخرى بدل تحميل الجدول بأكمله في الذاكرة أولاً.

    bash
    cat > /usr/local/bin/backup.sh << "SCRIPT"
    #!/bin/bash
    set -euo pipefail
    
    DB_NAME="myapp"
    BACKUP_DIR="/home/backups"
    DATE=$(date +%F)
    FILE="${BACKUP_DIR}/db_${DATE}.sql.gz"
    
    # تفريغ بدون قفل جداول، دفق إلى gzip
    ionice -c3 nice -n19 \
      mysqldump \
        --single-transaction \
        --quick \
        --skip-lock-tables \
        "${DB_NAME}" \
      | gzip -9 > "${FILE}"
    
    chmod 600 "${FILE}"
    
    # احتفظ بآخر 7 أيام فقط
    find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +7 -delete
    
    echo "[$(date)] اكتملت النسخة الاحتياطية: ${FILE} ($(du -sh ${FILE} | cut -f1))"
    SCRIPT
    
    chmod +x /usr/local/bin/backup.sh
  4. 4

    اختبر السكريبت يدوياً أولاً

    شغّل السكريبت يدوياً دائماً قبل جدولته. تحقق من أن ملف الإخراج موجود وحجمه أكبر من صفر.

    bash
    sudo /usr/local/bin/backup.sh
    
    # أكّد إنشاء الملف
    ls -lh /home/backups/
    
    # ألقِ نظرة على النسخة المضغوطة دون استخراجها
    gunzip -c /home/backups/db_$(date +%F).sql.gz | head -20
  5. 5

    جدوِل مع crontab

    شغّل النسخ الاحتياطي يومياً الساعة 02:00 كـ root. يعمل cron في بيئة بسيطة — استخدم المسارات المطلقة في كل مكان في السكريبت (منجز أعلاه بالفعل).

    bash
    # عدّل crontab الخاص بـ root
    sudo crontab -e
    
    # أضف هذا السطر:
    0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
    
    # اعرض المهام المجدولة لـ root
    sudo crontab -l
    
    # تأكد من أن السجل يلتقط الإخراج
    sudo tail -f /var/log/backup.log
  6. 6

    اختبر إجراء الاستعادة

    نسخة احتياطية لم تستعدها قط هي نسخة لا تملكها. اختبر على قاعدة بيانات staging لا على الإنتاج.

    bash
    # استعادة إلى قاعدة بيانات موجودة (سيُكتب فوق جميع البيانات)
    gunzip < /home/backups/db_2026-05-28.sql.gz | mysql myapp
    
    # استعادة إلى قاعدة بيانات جديدة (أكثر أماناً للاختبار)
    mysql -e "CREATE DATABASE myapp_restore;"
    gunzip < /home/backups/db_2026-05-28.sql.gz | mysql myapp_restore
    
    # تحقق من وجود الجداول الرئيسية
    mysql myapp_restore -e "SHOW TABLES; SELECT COUNT(*) FROM users;"
    
    # احذف قاعدة البيانات الاختبارية
    mysql -e "DROP DATABASE myapp_restore;"
  7. 7

    انسخ النسخ الاحتياطية خارج الخادم بـ rsync

    نسخة احتياطية على نفس خادم قاعدة البيانات تضيع إن مات الخادم. ادفعها إلى خادم ثانٍ عبر SSH. شغّل هذا في نفس مهمة cron بعد اكتمال التفريغ.

    bash
    # أضف في نهاية backup.sh (بعد سطر find -delete):
    
    REMOTE_USER="backup"
    REMOTE_HOST="backup-server.example.com"
    REMOTE_DIR="/home/backups/myapp/"
    
    rsync -az --delete \
      -e "ssh -i /root/.ssh/backup_key -o StrictHostKeyChecking=no" \
      "${BACKUP_DIR}/" \
      "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}"
    
    echo "[$(date)] تمت المزامنة مع الخادم البعيد: ${REMOTE_HOST}:${REMOTE_DIR}"
    
    # المتطلبات المسبقة:
    # 1. أنشئ مفتاحاً مخصصاً: ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N ""
    # 2. أضف المفتاح العام إلى authorized_keys الخادم البعيد
    # 3. أنشئ المجلد البعيد: ssh user@backup-server mkdir -p /home/backups/myapp
  8. 8

    راقب صحة النسخ الاحتياطية

    الفشل الصامت هو الأسوأ. أضف فحصاً للحجم وتنبيهاً حتى تعلم خلال ساعات إن توقف النسخ الاحتياطي عن العمل.

    bash
    # أضف إلى backup.sh بعد سطر gzip:
    FILE_SIZE=$(stat -c%s "${FILE}")
    MIN_SIZE=1024  # 1 KB حد أدنى — النسخة الصحيحة دائماً أكبر
    
    if [ "${FILE_SIZE}" -lt "${MIN_SIZE}" ]; then
      echo "خطأ: ملف النسخة الاحتياطية صغير بشكل مريب (${FILE_SIZE} بايت)" >&2
      # أرسل تنبيهاً بالبريد (يتطلب mailutils)
      echo "ربما فشلت النسخة الاحتياطية. تحقق من ${FILE}" | mail -s "تنبيه: فشل النسخ الاحتياطي" admin@example.com
      exit 1
    fi
    
    # تحقق من آخر نسخة احتياطية في أي وقت
    ls -lht /home/backups/ | head -3

نصائح ومحاذير

  • انسخ <strong>جميع</strong> قواعد البيانات دفعة واحدة بـ <code>mysqldump --all-databases</code> إن كان الخادم يشغّل مشاريع متعددة — مهمة cron واحدة وملف واحد.
  • استخدم خيارات <code>--routines --triggers --events</code> لتضمين الإجراءات المخزنة والـ triggers والأحداث المجدولة في التفريغ. إهمالها من الأخطاء الشائعة.
  • فضّل <code>--set-gtid-purged=OFF</code> عند التفريغ من replica لتجنب أخطاء GTID عند الاستعادة.
  • اختبر عملية الاستعادة كل ثلاثة أشهر — ليس فقط أن الملف موجود، بل أن قاعدة البيانات المستعادة تخدم تطبيقك بشكل صحيح.
  • خيارات التخزين السحابي: <code>rclone copy /home/backups/ s3:mybucket/db/</code> يعمل مباشرة مع S3 وBackblaze B2 وGoogle Cloud Storage. ثبّت rclone مرة واحدة، اضبطه مرة واحدة.

خاتمة

لديك الآن نسخ احتياطي يومي مؤتمت: بيانات اعتماد محمية، بدون قفل جداول، مضغوط بـ gzip، محتفظ به 7 أيام، ومنسوخ اختيارياً خارج الخادم. والأهم، اختبرت عملية الاستعادة — وهذا ما يفرق بين استراتيجية نسخ احتياطي حقيقية وشعور زائف بالأمان. أضف تذكيراً في تقويمك لتشغيل اختبار الاستعادة مجدداً بعد 3 أشهر.

#MySQL #Backup #Cron
العودة إلى جميع الأدلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.