یک شب، ساعت یازده، تلفن زنگ زد. کارفرمای یک فروشگاه اینترنتی، با صدای مضطرب می‌گفت که وسط یک آپدیت افزونه، سایتش به‌کلی از کار افتاده و پیشخوان باز نمی‌شود. صفحه‌ای سفید، دیتابیس در دسترس نیست، و آخرین بکاپ هفت ماه پیش گرفته شده بود. آن شب برای من درس بزرگی داشت: پشتیبان‌گیری از MySQL یک تصمیم جانبی نیست؛ بیمه‌نامه‌ای است که در بدترین شب پروژه، تفاوت بین «چند ساعت کار» و «چند ماه از‌دست‌رفتۀ کسب‌وکار» را می‌سازد. در همان پروژه، تیم توانست با یک بکاپ هفت‌ماهه و ترکیب لاگ‌های باینری، بخش بزرگی از داده را بازیابی کند؛ ولی سه روز کاری، فقط برای پیاده‌سازی و بازیابی صرف شد. در این مقاله، همان استراتژی‌ها و دستوراتی را مرور می‌کنم که امروز در هر پروژه‌ی جدید، از روز اول پیاده می‌کنم — از دستور پایه‌ی mysqldump تا بکاپ داغ، مهاجرت داده و آزمایش دوره‌ای بازیابی.

چرا پشتیبان‌گیری، بیمه‌نامه‌ی کسب‌وکار است؟

اگر تازه با MySQL آشنا می‌شوید، اول آموزش MySQL از صفر را بخوانید. اما فرض کنیم با مفاهیم پایه راحت هستید. حالا سؤال اصلی این است: چرا پشتیبان‌گیری، از هر دستور دیگری در MySQL مهم‌تر است؟

سه دلیل که در پروژه‌های واقعی به آن‌ها رسیده‌ام:

  • داده، تنها داراییِ غیرقابل‌بازسازی است: هاست را می‌توان عوض کرد، کد را می‌توان بازنویسی کرد، قالب را می‌توان دوباره خرید. ولی داده‌ی فروش، سفارش‌ها و مشتریان، دوباره ساخته نمی‌شود. بکاپ، بیمه‌نامه‌ی همین دارایی است.
  • خطای انسانی، همیشه در کمین است: یک DELETE بدون WHERE در ساعت شلوغی، یک UPDATE اشتباه، یا یک مهاجرت ناموفق — هر کدام می‌تواند داده را از بین ببرد. بکاپ، تنها راه بازگشت است.
  • بحران، بدون اعلام قبلی می‌آید: خرابی دیسک، هک، خطای سرور، حمله‌ی باج‌گیر — هیچ‌کدام وقت قبلی نمی‌گیرند. تنها چیزی که در آن لحظه نجات می‌دهد، بکاپی است که از قبل آماده و تست‌شده باشد.

یک نکته‌ی مهم که در پروژه‌های واقعی به آن رسیده‌ام: پشتیبان‌گیری، به‌ندرت جایگاه درستی در بودجه‌ی پروژه دارد. اکثر تیم‌ها، بودجه‌ی خود را برای توسعه‌ی ویژگی جدید خرج می‌کنند و بکاپ را به «فاز بعد» موکول می‌کنند. تجربه‌ی من این است که اولین بحران، دقیقاً همان لحظه‌ای رخ می‌دهد که هنوز بکاپ گرفته نشده — مثل همان شب ساعت یازده در مقدمه.

دیتابیس بدون بکاپ، مثل یک ساختمان بدون بیمه‌ی آتش‌سوزی است؛ تا روزی که آتش نگیرد، هزینه‌اش بی‌دلیل به نظر می‌رسد، و روزی که بگیرد، همه‌چیز دیر است.

استراتژی بکاپ: چهار تصمیم قبل از هر دستور

قبل از نوشتن هر اسکریپت بکاپ، چهار تصمیم راهبردی وجود دارد که در پروژه‌های واقعی، تفاوت بین یک استراتژی مؤثر و یک تمرین نمایشی را می‌سازد:

۱) چه چیزی را بکاپ بگیریم؟

سه سطح انتخاب دارید: کل سرور MySQL، یک دیتابیس خاص، یا یک جدول خاص. در پروژه‌های واقعی، اکثر مواقع دیتابیس‌محور بکاپ می‌گیرم — چون هر پروژه یا اپلیکیشن، دیتابیس خودش را دارد. بکاپ کل سرور، فقط وقتی منطقی است که یک سرور اختصاصی با چند پروژه داشته باشید. این تفکیک را در طراحی دیتابیس در MySQL در سطح ساختار هم دیده‌ام — هر پروژه، دیتابیس جداگانه.

۲) چقدر بکاپ بگیریم؟

تعداد نسخه‌های بکاپ، به میزان تغییرات داده بستگی دارد. سه حالت رایج:

  • روزانه: برای سایت‌هایی که روزانه محتوا یا سفارش جدید دارند.
  • ساعتی: برای فروشگاه‌های پرفروش یا سیستم‌های مالی که هر ساعت داده‌ی جدیدی ثبت می‌شود.
  • هفتگی: برای سایت‌های محتوایی که تغییراتشان کم است.

در پروژه‌های واقعی، معمولاً یک بکاپ «کامل هفتگی» و چند بکاپ «افزایشی روزانه» طراحی می‌کنم. این ترکیب، هم فضا را بهینه می‌کند و هم نقاط بازیابی مناسبی فراهم می‌آورد.

۳) چند نسخه نگه داریم؟

قاعده‌ی «۳-۲-۱» که در همه‌ی سیستم‌های جدی توصیه می‌شود:

  • ۳ نسخه از داده داشته باشید.
  • در ۲ رسانه‌ی مختلف ذخیره کنید (مثلاً دیسک محلی و فضای ابری).
  • ۱ نسخه را در جای جغرافیایی متفاوت نگه دارید (مثلاً سرور دیگر یا فضای ابری خارج از کشور).

تجربه‌ی من: در پروژه‌ای که همه‌ی بکاپ‌ها روی همان سرور دیتابیس بود، یک حمله‌ی باج‌گیر، هم داده‌ی فعال و هم بکاپ‌ها را رمزگذاری کرد. اگر نسخه‌ی بیرون‌سروری داشتیم، از دست نمی‌رفت.

۴) چه چیزی را بکاپ نگیریم؟

در پروژه‌های واقعی، بخش زیادی از داده‌ها قابل بازسازی است و نیازی به بکاپ ندارد: جدول‌های موقت، کش، لاگ‌های قدیمی. حذف این‌ها از بکاپ، حجم را به‌شدت کاهش می‌دهد و سرعت بکاپ را بالا می‌برد. اگر با دستورات پرکاربرد MySQL آشنایی کم دارید، دستورات پرکاربرد MySQL فهرستی از ابزارهای بررسی حجم جدول‌ها را در اختیارتان می‌گذارد.

بکاپ منطقی با mysqldump

ابزار پایه و پرکاربرد بکاپ در MySQL، mysqldump است که یک بکاپ منطقی می‌سازد: مجموعه‌ای از دستورات SQL که هنگام بازیابی، همه‌ی ساختار و داده را بازسازی می‌کنند.

بکاپ پایه

mysqldump -u db_user -p mydb > mydb_backup.sql

بکاپ با ساختار، داده، و رویه‌های ذخیره‌شده

mysqldump -u db_user -p \
    --routines \
    --triggers \
    --events \
    --single-transaction \
    mydb > mydb_full_backup.sql

چهار گزینه‌ی مهم در این دستور که در پروژه‌های واقعی به آن‌ها رسیده‌ام:

  • --routines: رویه‌های ذخیره‌شده (Stored Procedures) و توابع را هم بکاپ می‌گیرد. بدون این گزینه، اگر برنامه‌ی شما به رویه‌های ذخیره‌شده وابسته باشد، بازیابی ناقص می‌شود.
  • --triggers: تریگرها را بکاپ می‌گیرد. اهمیت این گزینه، وقتی خودش را نشان می‌دهد که تریگرها منطق کسب‌وکار را در سطح دیتابیس پیاده کرده باشند.
  • --events: رویدادهای زمان‌بندی‌شده را بکاپ می‌گیرد. اگر از MySQL Events استفاده می‌کنید، این گزینه ضروری است.
  • --single-transaction: بکاپ را در یک تراکنش انجام می‌دهد و از قفل‌کردن جدول‌های InnoDB جلوگیری می‌کند. این گزینه، برای سایت‌های فعال، حیاتی است — بدون آن، در طول بکاپ، INSERTهای کاربران قفل می‌شوند.

نکته‌ی مهم: --single-transaction فقط روی جدول‌های InnoDB کار می‌کند. اگر پروژه‌ی شما هنوز روی MyISAM است، این گزینه به‌کار نمی‌آید. اگر با تفاوت این دو موتور درگیرید، تفاوت InnoDB و MyISAM مسیر مهاجرت را نشان می‌دهد.

بکاپ فشرده

mysqldump -u db_user -p mydb | gzip > mydb_backup.sql.gz

در پروژه‌های واقعی، فشرده‌سازی می‌تواند حجم را تا ۷۰-۸۰ درصد کاهش دهد. برای سایت‌های متوسط، تفاوت بین چند صد مگابایت و چند ده مگابایت است — که در سرعت انتقال به فضای ابری یا دیسک بیرونی، محسوس است.

بکاپ فقط ساختار بدون داده

mysqldump -u db_user -p --no-data mydb > mydb_schema.sql

در پروژه‌های واقعی، این نوع بکاپ برای دو کاربرد استفاده می‌شود: انتقال ساختار به محیط development، و نسخه‌بندی schema در مخزن کد (همراه با migrationها).

بکاپ فقط داده بدون ساختار

mysqldump -u db_user -p --no-create-info mydb > mydb_data.sql

این شکل، برای زمانی مناسب است که ساختار ثابت است و فقط می‌خواهید داده را منتقل کنید. تجربه‌ی من: در پروژه‌هایی که migrationساختار جداگانه دارند، بکاپ داده تنها، ابزار مفیدی برای همگام‌سازی محیط staging با production است.

بکاپ فیزیکی و بکاپ داغ

mysqldump یک بکاپ منطقی است و برای دیتابیس‌های متوسط بی‌نظیر است، ولی در دیتابیس‌های بزرگ (بیش از چند صد گیگابایت)، بکاپ منطقی می‌تواند ساعت‌ها طول بکشد. راه‌حل، بکاپ فیزیکی است که فایل‌های داده را مستقیماً کپی می‌کند.

Percona XtraBackup

ابزار محبوب و متن‌باز برای بکاپ داغ InnoDB. اجازه می‌دهد دیتابیس را بدون توقف، بکاپ بگیرید:

xtrabackup --backup --target-dir=/backup/mysql --user=db_user --password=pass

سه مزیت بکاپ داغ که در پروژه‌های واقعی به آن‌ها رسیده‌ام:

  • بدون توقف: سایت در طول بکاپ فعال می‌ماند و کاربران تجربه‌ی کندی حس نمی‌کنند.
  • سرعت بالاتر: بکاپ فایل‌های داده، چند برابر سریع‌تر از mysqldump روی دیتابیس‌های بزرگ است.
  • بازگشت سریع‌تر: بازیابی از بکاپ فیزیکی، چند برابر سریع‌تر از اجرای یک فایل SQL بزرگ است.

Snapshot در سطح زیرساخت

اگر دیتابیس شما روی یک VM یا VPS با قابلیت Snapshot است، می‌توانید از Snapshot دیسک استفاده کنید. برای این کار، باید:

  1. دیتابیس را در حالت آماده‌ی Snapshot قرار دهید (FLUSH TABLES WITH READ LOCK).
  2. Snapshot دیسک را بگیرید.
  3. قفل را آزاد کنید (UNLOCK TABLES).

تجربه‌ی من: در پروژه‌های ابری، Snapshot سریع‌ترین روش بکاپ است، ولی به دو شرط کار می‌کند: زیرساخت شما این قابلیت را دارد، و از قفل‌های لازم آگاه هستید. Snapshot بدون قفل، ممکن است بکاپی ناسازگار تولید کند — چیزی که فقط در روز بازیابی خودش را نشان می‌دهد.

Binary Log و بازیابی نقطه‌ای

یکی از ابزارهای قدرتمند MySQL که در پروژه‌های واقعی، تفاوت بین «بازگشت به بکاپ دیروز» و «بازگشت به دقیقه‌ی قبل از حادثه» را می‌سازد، Binary Log است. این لاگ، تمام تغییرات دیتابیس را ثبت می‌کند و امکان بازیابی نقطه‌ای (Point-in-Time Recovery) را فراهم می‌کند.

فعال‌سازی Binary Log

# در my.cnf
[mysqld]
log-bin = /var/log/mysql/mysql-bin
server-id = 1
expire_logs_days = 7
max_binlog_size = 100M

سه گزینه‌ی مهم:

  • log-bin: مسیر ذخیره‌ی فایل‌های binary log.
  • expire_logs_days: چند روز لاگ نگه داشته شود. مقدار پیش‌فرض من ۷ روز است — برای اکثر پروژه‌ها کافی است و فضای دیسک را کنترل می‌کند.
  • max_binlog_size: اندازه‌ی هر فایل لاگ. مقدار ۱۰۰ مگابایت، تعادل خوبی است.

بازیابی نقطه‌ای

فرض کنید امروز ساعت ۱۰ صبح، یک DELETE اشتباه، هزاران رکورد را پاک کرده است. سناریوی بازیابی:

  1. بکاپ دیشب را بازیابی کنید — این بازیابی، شما را به وضعیت ساعت ۲۳ دیشب می‌برد.
  2. Binary logهای بعد از بکاپ را با mysqlbinlog استخراج کنید.
  3. آن‌ها را تا دقیقه‌ی قبل از حادثه (ساعت ۰۹:۵۹) اجرا کنید.
mysqlbinlog --start-datetime="2026-09-16 23:00:00" \
            --stop-datetime="2026-09-17 09:59:00" \
            /var/log/mysql/mysql-bin.000123 \
    | mysql -u db_user -p mydb

تجربه‌ی من: در پروژه‌ای که یک توسعه‌دهنده، سه‌هزار سفارش را با یک کوئری اشتباه حذف کرده بود، بازیابی نقطه‌ای نجات‌دهنده بود — چون فقط ۱۸۰ ثانیه از دست رفت، نه یک روز کامل. بدون Binary Log، مجبور بودیم به بکاپ دیشب برگردیم و هزاران سفارش بعدی را هم از دست بدهیم.

بکاپ، فقط نقطه‌ی شروع است؛ Binary Log، پلی است که شما را از آن نقطه، تا دقیقه‌ی قبل از حادثه می‌رساند.

خودکارسازی بکاپ

بکاپی که دستی گرفته می‌شود، دیر یا زود فراموش می‌شود. در پروژه‌های واقعی، خودکارسازی بکاپ، اولین کاری است که پس از استقرار دیتابیس انجام می‌دهم.

اسکریپت ساده با Cron

#!/bin/bash
# /usr/local/bin/db_backup.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/mysql"
DB_NAME="mydb"
DB_USER="backup_user"
DB_PASS="$(cat /etc/secrets/db_password)"

# بکاپ با فشرده‌سازی
mysqldump -u "$DB_USER" -p"$DB_PASS" \
    --single-transaction \
    --routines --triggers --events \
    "$DB_NAME" | gzip > "$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"

# حذف بکاپ‌های قدیمی‌تر از ۳۰ روز
find "$BACKUP_DIR" -name "${DB_NAME}_*.sql.gz" -mtime +30 -delete

echo "Backup completed: ${DB_NAME}_${DATE}.sql.gz"

و در crontab:

# هر شب ساعت ۲ بامداد
0 2 * * * /usr/local/bin/db_backup.sh >> /var/log/db_backup.log 2>&1

سه نکته‌ی مهم در اسکریپت بالا که در پروژه‌های واقعی به آن‌ها رسیده‌ام:

  • رمز عبور در اسکریپت نباشد: همان اصل که در مدیریت رمز عبور امن رویش تأکید کرده‌ام. رمز باید از فایل خارج از مخزن یا متغیر محیطی خوانده شود.
  • لاگ خروجی: هر بکاپ، یک خط لاگ بنویسد. اگر بکاپ شکست خورد، باید بدانید — بدون لاگ، یک بکاپ ناموفق، بی‌صدا از بین می‌رود.
  • حذف خودکار بکاپ‌های قدیمی: بدون این، دیسک شما در چند ماه پر می‌شود. مقدار ۳۰ روز، تعادل خوبی است — برای اکثر پروژه‌ها کافی است و فضای دیسک را کنترل می‌کند.

ابزارهای حرفه‌ای‌تر

برای پروژه‌های بزرگ‌تر، ابزارهایی مثل automysqlbackup یا ابزارهای پشتیبان‌گیری هاست، قابلیت‌های بیشتری دارند: بکاپ افزایشی، فشرده‌سازی هوشمند، و ارسال به فضای ذخیره‌سازی خارجی. اگر با هاست اشتراکی کار می‌کنید، ابزارهای cPanel و DirectAdmin، معمولاً بکاپ خودکار دارند. اصول کار با cPanel در cPanel چیست و چه کاربردهایی دارد و روش پشتیبان‌گیری از آن در پشتیبان‌گیری در cPanel آمده است.

ذخیره‌سازی: کجا نگه داریم؟

یکی از مهم‌ترین تصمیم‌ها در استراتژی بکاپ، انتخاب محل ذخیره‌سازی است. تجربه‌ی من این است که محل ذخیره، به‌اندازه‌ی خودِ بکاپ اهمیت دارد — چون بکاپی که در جای اشتباه ذخیره شود، در روز بحران، وجود ندارد.

گزینه‌های ذخیره‌سازی

گزینهمزیتهشدار
دیسک همان سرورساده و سریعدر حمله یا خرابی دیسک، از بین می‌رود
دیسک خارجی متصلسریع، مستقل از دیتابیسدر صورت خرابی سرور، احتمال آسیب هم دارد
FTP/SFTP به سرور دیگرمستقل از سرور اصلینیاز به پیکربندی و امنیت
فضای ابری (S3، Drive، Backblaze)مقاوم، مقیاس‌پذیرهزینه و نیاز به اینترنت پایدار
Object Storage اختصاصیبهترین تعادل هزینه و امنیتنیاز به پیکربندی

توصیه‌ی من در پروژه‌های واقعی، ترکیب سه‌گانه‌ی «۳-۲-۱» است:

  • یک نسخه روی همان سرور: برای بازیابی سریع روزمره (مثلاً بازیابی جدولی که اشتباهاً تغییر کرده).
  • یک نسخه روی فضای ابری: برای بازیابی در صورت خرابی کامل سرور.
  • یک نسخه آفلاین هفتگی: برای بحران‌های بزرگ (حمله‌ی باج‌گیر، حذف حساب کاربری ابری و…).

رمزنگاری بکاپ

بکاپی که رمزنگاری نشده باشد، اگر به دست اشتباهی بیفتد، تمام داده‌ی کسب‌وکار شما را لو می‌دهد. برای پروژه‌های حساس، بکاپ را رمزنگاری کنید:

mysqldump -u db_user -p mydb | gzip | \
    openssl enc -aes-256-cbc -salt -out mydb_backup.sql.gz.enc

هنگام بازیابی:

openssl enc -d -aes-256-cbc -in mydb_backup.sql.gz.enc | \
    gunzip | mysql -u db_user -p mydb

اگر با مفهوم رمزنگاری دیتابیس در سطح دیگری هم درگیر هستید، رمزنگاری دیتابیس تفاوت‌های رمزنگاری در حال انتقال و در حالت سکون را توضیح می‌دهد.

بازیابی: تمرین واقعی

یک بکاپ، فقط وقتی بکاپ است که بازیابی‌اش تست شده باشد. بدون آزمایش، بکاپ شما فقط یک فایل است — و در روز بحران، ممکن است کشف کنید که فایل خراب است یا روش بازیابی اشتباه است.

بازیابی پایه

# ساخت دیتابیس جدید
mysql -u root -p -e "CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"

# بازیابی از بکاپ
mysql -u root -p mydb < mydb_backup.sql

بازیابی از بکاپ فشرده

gunzip < mydb_backup.sql.gz | mysql -u db_user -p mydb

بازیابی بخشی

گاهی نمی‌خواهید کل دیتابیس را بازیابی کنید؛ فقط یک جدول خاص. mysqldump این امکان را می‌دهد:

# بکاپ فقط یک جدول
mysqldump -u db_user -p mydb users > users_backup.sql

# بازیابی همان جدول
mysql -u db_user -p mydb < users_backup.sql

تجربه‌ی من: در پروژه‌ای که یک مهاجرت ناقص، جدول دسته‌بندی‌ها را خراب کرده بود، بازیابی فقط همان جدول از بکاپ دیشب، سایت را در چند دقیقه به کار انداخت. اگر بکاپی به‌صورت یکجا بود و فقط برای بازیابی کل دیتابیس طراحی شده بود، باید ساعت‌ها صبر می‌کردیم.

آزمایش دوره‌ای بازیابی

در پروژه‌های واقعی، توصیه می‌کنم ماهی یک‌بار، یک آزمایش بازیابی انجام دهید:

  1. یک بکاپ اخیر را در محیط staging بازیابی کنید.
  2. تعدادی از رکوردهای کلیدی را بازبینی کنید (مثلاً آخرین سفارش‌ها).
  3. برنامه را روی آن دیتابیس اجرا کنید و مطمئن شوید همه‌چیز کار می‌کند.

این تمرین ماهانه، هم روش بازیابی را در ذهن تیم تازه می‌کند و هم بکاپ‌های ناسالم را پیش از بحران لویش می‌دهد. اگر بعد از بازیابی، برنامه خطاهای عجیب داد — مثل خطای UnicodeDecodeError در پایتون — قبل از هر چیز انکودینگ بکاپ را چک کنید. اصول رفع این خطا در رفع خطای UnicodeDecodeError در پایتون آمده است.

بکاپی که بازیابی‌اش تست نشده، بکاپ نیست؛ فقط یک فایل امیدبخش است.

بکاپ MySQL در بستر وردپرس

بخش بزرگی از پروژه‌های من روی وردپرس است و بکاپ دیتابیس آن، به‌دلیل ساختار خاص و حجم زیاد جداول wp_options و wp_postmeta، نکات ویژه‌ای دارد. اگر با ساختار وردپرس آشنایی کم دارید، وردپرس چیست نقطه‌ی شروع خوبی است.

بکاپ دستی دیتابیس وردپرس

mysqldump -u wp_user -p \
    --single-transaction \
    --routines \
    --triggers \
    wp_database > wp_backup_$(date +%Y%m%d).sql

نکات خاص وردپرس که در پروژه‌های واقعی به آن‌ها رسیده‌ام:

  • پیشوند جداول را حتماً چک کنید: پیشوند پیش‌فرض wp_ است، ولی بسیاری از سایت‌ها آن را به دلایل امنیتی تغییر داده‌اند. قبل از هر بکاپ، از wp-config.php مقدار $table_prefix را بخوانید.
  • جدول wp_options را جدی بگیرید: این جدول شامل تنظیمات سایت، URLها و بسیاری از داده‌های مهم است. اگر بکاپ شما فقط جداول محتوایی را می‌گیرد، خیلی از تنظیمات از دست می‌رود.
  • روی سایت فعال با --single-transaction: بدون این گزینه، در حین بکاپ، سایت ممکن است برای کاربران قفل شود.

افزونه‌های بکاپ وردپرس

در پروژه‌های وردپرسی که دسترسی SSH به هاست ندارند، افزونه‌های بکاپ ابزار اصلی هستند. مقایسه‌ی کامل افزونه‌های بکاپ در بهترین افزونه‌های بکاپ وردپرس آمده است. روش دستی بکاپ از پیشخوان در چگونه از سایت وردپرسی بکاپ بگیریم گام‌به‌گام توضیح داده شده. برای فروشگاه‌های ووکامرسی، که حجم داده‌ی سفارش بالا و متغیر است، بکاپ اختصاصی در بکاپ ووکامرس بررسی شده است.

پشتیبان‌گیری از دیتابیس‌های بزرگ

وقتی دیتابیس از چند ده گیگابایت عبور می‌کند، بکاپ منطقی با mysqldump دیگر گزینه‌ی مناسبی نیست. سه راه‌حل که در پروژه‌های واقعی به‌کارم آمده:

۱) بکاپ فیزیکی با XtraBackup

همان‌طور که در بخش قبل گفتیم، XtraBackup بکاپ را از فایل‌های داده‌ی InnoDB می‌سازد. برای دیتابیس‌های صد‌ها گیگابایتی، تنها گزینه‌ی عملی است.

۲) بکاپ تکه‌تکه با mysqldump

اگر mysqldump را ترجیح می‌دهید، می‌توانید جدول‌ها را جداگانه بکاپ بگیرید:

for table in $(mysql -u db_user -p -N -e "SHOW TABLES FROM mydb"); do
    mysqldump -u db_user -p --single-transaction mydb "$table" | \
        gzip > "/backup/${table}.sql.gz"
done

این روش، مزیت مهمی دارد: اگر یکی از جدول‌ها خراب شود، فقط همان را باید دوباره بازیابی کنید. ولی عیبش این است که کل بکاپ، یکپارچه نیست — اگر بین بکاپ دو جدول، تراکنشی کامل شود، ممکن است بازیابی، ناسازگاری داشته باشد.

۳) استریم مستقیم به فضای ابری

mysqldump -u db_user -p mydb | gzip | \
    aws s3 cp - s3://my-backups/mydb_$(date +%Y%m%d).sql.gz

این الگو، بدون نیاز به فضای موقت روی دیسک، بکاپ را مستقیم به S3 منتقل می‌کند. تجربه‌ی من: در پروژه‌ای با دیتابیس ۲۰۰ گیگابایتی و فضای دیسک محدود، این روش، تنها راه ممکن بود. اگر با مدیریت و بهینه‌سازی دیتابیس‌های بزرگ درگیرید، بهینه‌سازی جداول MySQL برای سرعت بیشتر نکات مکملی دارد.

اشتباهاتی که در پروژه‌های واقعی دیده‌ام

در بازبینی استراتژی‌های بکاپ در پروژه‌های مختلف، این اشتباهات را زیاد دیده‌ام:

  • بکاپ فقط روی همان سرور: اگر سرور از دست برود، هم داده و هم بکاپ می‌رود. در حمله‌ی باج‌گیر، هر دو رمزنگاری می‌شوند.
  • بکاپ بدون تست بازیابی: همان اشتباه کلاسیک. یک فایل SQL روی دیسک که هیچ‌وقت بازیابی نشده، ممکن است خراب یا ناقص باشد.
  • بکاپ دستی و فراموش‌شده: بکاپ‌هایی که «من یادم می‌آید» گرفته می‌شوند، وقتی همه‌چیز خوب است گرفته می‌شوند و در بحران، دو ماه پیشین است. خودکارسازی، راه‌حل این مشکل است.
  • عدم فشرده‌سازی: بکاپ خام، چند برابر فشرده فضا می‌گیرد. برای پروژه‌های با داده‌ی زیاد، فشرده‌سازی تفاوت بین «چند ماه فضای دیسک» و «چند هفته» است.
  • نبود رمزنگاری برای بکاپ‌های حساس: بکاپ روی فضای ابری، بدون رمزنگاری، در صورت نشت اطلاعات، فاجعه‌ی حریم خصوصی است. این نکته در پروژه‌هایی که با GDPR سر و کار دارند، حیاتی است — GDPR و تأثیر آن بر وب‌سایت‌های ایرانی لایه‌های قانونی این موضوع را توضیح می‌دهد.
  • فراموش کردن رویه‌ها و تریگرها: بکاپ بدون --routines --triggers --events، ساختار دیتابیس را ناقص ذخیره می‌کند. در بازیابی، برنامه خطاهای عجیب می‌دهد که پیدا کردن ریشه‌شان ساعت‌ها طول می‌کشد.
  • نبود مستندسازی روش بازیابی: در روز بحران، هیچ‌کس نمی‌داند کدام بکاپ، کجا و چطور باید بازیابی شود. یک سند ساده «راهنمای بازیابی بحران» که در تیم به اشتراک گذاشته شود، این ابهام را از بین می‌برد.
  • بکاپ بدون بررسی انکودینگ: همان داستان همیشگی متن فارسی. اگر بکاپ و بازیابی با انکودینگ اشتباه انجام شود، داده‌ی فارسی به کاراکترهای عجیب تبدیل می‌شود. برای متن فارسی، همیشه utf8mb4 را در بکاپ و بازیابی صریح مشخص کنید.
  • نبود نسخه‌بندی بکاپ‌ها: اگر بکاپ‌ها با همان نام ذخیره می‌شوند، هر بار روی بکاپ قبلی بازنویسی می‌شوند. همیشه تاریخ و زمان را در نام فایل بگذارید.
  • عدم پایش فضای دیسک: بکاپ‌های انباشته، دیسک سرور را پر می‌کنند و در نهایت، سایت از کار می‌افتد. یک سیاست حذف خودکار (مثلاً بکاپ‌های قدیمی‌تر از ۳۰ روز) ضروری است.
  • بکاپ در ساعت شلوغی: بکاپ روی دیتابیس فعال با mysqldump و بدون --single-transaction، جدول‌ها را قفل می‌کند و سایت را کند. بکاپ را در ساعت کم‌ترافیک یا با گزینه‌ی مناسب بگیرید.
  • نادیده‌گرفتن Binary Log: بدون Binary Log، بازیابی نقطه‌ای ممکن نیست و در بحران، مجبورید کل داده‌ی یک روز را از دست بدهید. فعال‌سازی Binary Log، یک خط تنظیم در my.cnf است.
  • اعتماد به بکاپ هاست: بکاپ هاست، معمولاً برای بازیابی کامل سایت کافی است، ولی اگر فقط یک جدول را می‌خواهید بازیابی کنید، انعطاف کمتری دارد. در پروژه‌های واقعی، بکاپ اختصاصی دیتابیس، مکمل بکاپ هاست است.
  • نبود نقش مشخص در تیم: در تیم‌های چندنفره، اگر مسئول بکاپ مشخص نباشد، هرکس فکر می‌کند دیگری انجام می‌دهد. تعیین صریح مسئولیت، بخشی از انضباط عملیاتی است.

یک توصیه‌ی عملی از تجربه: بکاپ را مثل کد ببینید — نسخه‌بندی، تست دوره‌ای، و مستندسازی می‌خواهد. اگر بکاپ‌های شما در یک فایل BACKUP.md مستند شده باشند و اسکریپت‌های بکاپ در مخزن کد نگهداری شوند، تیم جدید می‌تواند در چند دقیقه، همان استراتژی را درک و اجرا کند. اگر با امنیت دیتابیس در سطح وسیع‌تر هم درگیرید، امنیت دیتابیس چیست و سیاست‌های رمزنگاری و نگهداری بکاپ لایه‌های مکمل را نشان می‌دهند — و برای بکاپ کل سایت (شامل فایل‌ها)، چگونه از سایت وردپرسی بکاپ بگیریم و بازیابی سایت از بکاپ مسیر کامل را گام‌به‌گام توضیح می‌دهند.

سخن آخر

پشتیبان‌گیری از MySQL، از یک دستور mysqldump شروع می‌شود ولی در پروژه‌های واقعی، به یک سیستم چندلایه تبدیل می‌شود: استراتژی مشخص، خودکارسازی، ذخیره‌سازی چندنقطه‌ای، رمزنگاری، و آزمایش دوره‌ای بازیابی. سه نکته‌ی اصلی که در این مقاله به آن‌ها رسیدیم: اول، بکاپی که تست بازیابی نشده باشد، بکاپ نیست — یک تمرین ماهانه، جلوی بسیاری از بحران‌ها را می‌گیرد؛ دوم، ذخیره‌سازی چندنقطه‌ای (قاعده‌ی ۳-۲-۱) الزامی است — بکاپی که فقط روی همان سرور باشد، در بحران واقعی، وجود ندارد؛ سوم، Binary Log را جدی بگیرید — این ابزار، تفاوت بین بازیابی نقطه‌ای و بازگشت به یک روز قبل را می‌سازد.

اگر امروز می‌خواهید شروع کنید، سه کار کوچک پیشنهاد می‌کنم: همین امروز یک بکاپ دستی از دیتابیس اصلی‌تان بگیرید و در جای دیگری غیر از سرور اصلی ذخیره کنید؛ یک اسکریپت بکاپ خودکار با cron راه‌اندازی کنید؛ و ماه آینده، یک آزمایش بازیابی روی محیط staging انجام دهید. همین سه کار، در بیشتر پروژه‌ها، سطح امنیت و آرامش تیم را به‌طور محسوس بالا می‌برد. اگر تجربه‌ای از پشتیبان‌گیری در پروژه‌های خودتان دارید — مخصوصاً اگر در یک حادثه‌ی واقعی، بکاپ نجاتتان داده یا نبودش شما را در موقعیت سختی قرار داده — در دیدگاه‌ها بنویسید؛ همین نکته‌های میدانی، برای خواننده‌ی بعدی از هر مستند رسمی ارزشمندتر است. 💾