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

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

۶ دقیقه به‌روزرسانی ۱۳ آبان ۱۴۰۵

دستور rsync را زده‌اید، نوار پیشرفت روی ۴۰ درصد مانده و بعد از ده دقیقه اتصال SSH قطع شده است. حالا نمی‌دانید فایل‌های نیمه‌منتقل‌شده را پاک کنید یا از همان‌جا ادامه دهید. این دقیقاً همان نقطه‌ای است که تصمیم‌های اشتباه شروع می‌شود. انتقال بین سرور وقتی درست انجام می‌شود که پیش از زدن دستور، حجم داده، پهنای باند و روش راستی‌آزمایی را مشخص کرده باشید.

اول حجم و نوع داده را اندازه بگیرید، بعد ابزار را انتخاب کنید

قبل از هر چیز روی مبدأ این را اجرا کنید:

du -sh /var/www /home /var/lib/mysql
df -h
df -i

خروجی df -i را دست‌کم نگیرید. اگر inode مبدأ پر باشد، انتقال فایل‌های کوچک زیاد ممکن است در مقصد با خطای No space left on device متوقف شود، در حالی که df -h هنوز فضای آزاد نشان می‌دهد. جزئیات بیشتر دربارهٔ خواندن همین خروجی‌ها در دستورات دیسک در لینوکس: فضا، inode و سلامت دیسک آمده است.

برای انتخاب ابزار، این جدول را در نظر بگیرید:

حجم دادهابزار پیشنهادیدلیل
کمتر از ۱ گیگابایتscp یا rsyncسرعت راه‌اندازی مهم‌تر از بهینه‌سازی است
۱ تا ۵۰۰ گیگابایتrsync روی SSHقابل ادامه، قابل تکرار، قابل حذف فایل‌های اضافه
بیش از ۵۰۰ گیگابایتrsync یا tar + netcatکاهش سربار رمزنگاری در شبکهٔ داخلی
دیتابیس فعالdump + انتقال فایل dumpکپی فایل خام MySQL معمولاً خراب می‌شود

انتقال بین سرور در شبکهٔ داخلی یک دیتاسنتر با پهنای باند ۱ گیگابیت بر ثانیه، در حالت واقعی حدود ۱۰۰ تا ۱۱۰ مگابایت بر ثانیه جابه‌جا می‌کند. اگر روی همان لینک رمزنگاری SSH هم فعال باشد، این عدد به ۶۰ تا ۸۰ مگابایت بر ثانیه می‌رسد. برای ۲۰۰ گیگابایت داده، این تفاوت یعنی حدود ۴۰ دقیقه اختلاف.

دستور rsync درست برای انتقال بین سرور

این دستور را از روی سرور مقصد اجرا کنید، نه مبدأ:

rsync -avzP --partial --append-verify \
  -e "ssh -p 22 -o ServerAliveInterval=30" \
  root@192.0.2.10:/var/www/ /var/www/

چند نکته که در عمل تفاوت ایجاد می‌کند:

  • -P ترکیب --partial و --progress است؛ فایل نیمه‌کاره را نگه می‌دارد تا اجرای بعدی از همان‌جا ادامه دهد.
  • --append-verify فقط وقتی معنا دارد که فایل مبدأ فقط اضافه شده باشد. برای فایل‌هایی که وسطشان تغییر می‌کند، نتیجه اشتباه می‌دهد.
  • ServerAliveInterval=30 جلوی قطع شدن اتصال در انتقال‌های طولانی را می‌گیرد.
  • اسلش انتهای مسیر مبدأ مهم است. /var/www/ محتوای پوشه را کپی می‌کند، /var/www خود پوشه را.

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

این‌جا اشتباه می‌کنند

اشتباه رایج این است که کاربر --delete را در اجرای اول اضافه می‌کند. اگر مسیر مقصد اشتباه تایپ شده باشد، rsync با خیال راحت محتوای آن پوشه را پاک می‌کند. نشانه‌اش هم واضح است: انتقال بدون خطا تمام می‌شود، اما حجم دادهٔ منتقل‌شده کمتر از حد انتظار است و فایل‌های مقصد ناپدید شده‌اند. --delete را فقط در اجرای دوم یا سوم بگذارید، آن هم بعد از --dry-run.

انتقال دیتابیس MySQL بدون خرابی

کپی کردن مستقیم /var/lib/mysql روی سرور در حال کار، تقریباً همیشه به دیتابیس خراب منتهی می‌شود. روش درست:

mysqldump --single-transaction --routines --triggers \
  --databases shop_db > /tmp/shop_db.sql
gzip /tmp/shop_db.sql
rsync -avzP /tmp/shop_db.sql.gz root@192.0.2.20:/tmp/

سپس روی مقصد:

gunzip < /tmp/shop_db.sql.gz | mysql
mysql -e "SELECT COUNT(*) FROM shop_db.orders;"

گزینهٔ --single-transaction فقط روی InnoDB معنا دارد. اگر جدول MyISAM دارید، باید دیتابیس را قفل کنید یا از روش دیگری استفاده کنید. برای دیتابیس‌های بزرگ‌تر از ۵۰ گیگابایت، dump کردن و انتقال یکجا ممکن است ساعت‌ها طول بکشد و فضای دیسک مقصد را پر کند؛ در این حالت بهتر است dump را تکه‌تکه یا با ابزارهایی مثل mydumper بگیرید.

راستی‌آزمایی: کاری که اکثر افراد رد می‌کنند

انتقال تمام شده، اما آیا داده سالم است؟ این را روی هر دو سرور اجرا کنید و خروجی را مقایسه کنید:

find /var/www -type f -exec md5sum {} \; | sort -k2 | md5sum

اگر هش یکسان بود، انتقال کامل است. اگر نبود، با rsync -avzP --checksum دوباره اجرا کنید تا فقط فایل‌های متفاوت منتقل شوند. برای دیتابیس، تعداد رکوردها و حجم جدول‌ها را با SHOW TABLE STATUS مقایسه کنید.

یک نکته که کمتر گفته می‌شود: اگر روی سرور مقصد سرویس‌هایی مثل Nginx یا PHP-FPM در حال اجرا باشند، ممکن است فایل‌های موقت یا لاگ ایجاد کنند و مقایسهٔ هش را به‌هم بزنند. قبل از راستی‌آزمایی، سرویس‌های مقصد را متوقف کنید. محل نوشتن لاگ‌ها را در محل لاگ لینوکس: هر سرویس کجا می‌نویسد؟ می‌توانید ببینید.

انتقال بین سرورهای ابری و اختصاصی

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

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

iperf3 -c 192.0.2.20 -t 30

اگر عدد به‌دست‌آمده کمتر از ۲۰ مگابایت بر ثانیه بود، انتقال ۱۰۰ گیگابایت بیش از یک ساعت و نیم طول می‌کشد. در این حالت، فشرده‌سازی قبل از انتقال (مثلاً tar czf روی داده‌های متنی) می‌تواند زمان را به‌طور محسوسی کاهش دهد، به شرطی که CPU گلوگاه نشود.

فایروال و پورت‌ها را فراموش نکنید

اگر انتقال با خطای Connection refused یا No route to host متوقف شد، احتمالاً پورت SSH روی مقصد بسته است یا فایروال مبدأ اجازهٔ خروج نمی‌دهد. مرجع سریع دستورات در دستورات فایروال لینوکس: مرجع سریع iptables، nftables و ufw موجود است. پورت‌های پیش‌فرض سرویس‌ها را هم در مرجع پورت سرویس‌های پرکاربرد می‌توانید ببینید.

پرسش‌های پرتکرار

چرا rsync فایل‌های تکراری را دوباره منتقل می‌کند؟

اگر زمان تغییر فایل (mtime) یا اندازهٔ آن تغییر کرده باشد، rsync آن را دوباره می‌فرستد. برای جلوگیری از این حالت، از گزینهٔ --checksum استفاده کنید تا مقایسه بر اساس هش محتوا انجام شود، نه زمان. این کار CPU بیشتری مصرف می‌کند اما در انتقال‌های مکرر دقیق‌تر است.

آیا می‌توان انتقال بین سرور را در پس‌زمینه اجرا کرد؟

بله. با screen یا tmux یک نشست باز کنید و دستور را داخل آن اجرا کنید. اگر SSH قطع شود، انتقال ادامه پیدا می‌کند. روش دیگر استفاده از nohup است، اما در آن حالت خروجی پیشرفت را نمی‌بینید و اشکال‌زدایی سخت‌تر می‌شود.

انتقال بین سرور با پهنای باند کم چقدر طول می‌کشد؟

زمان انتقال برابر است با حجم داده تقسیم بر سرعت واقعی لینک. برای ۱۰۰ گیگابایت روی لینک ۱۰۰ مگابیت بر ثانیه، در حالت ایده‌آل حدود دو ساعت و نیم، و در عمل بیشتر. همیشه با iperf3 سرعت واقعی را اندازه بگیرید، نه سرعت اسمی.

بعد از انتقال، DNS را چه زمانی تغییر دهم؟

اول راستی‌آزمایی را کامل کنید، بعد رکورد DNS را عوض کنید. مقدار TTL رکورد را حداقل ۲۴ ساعت قبل از تغییر به ۳۰۰ ثانیه کاهش دهید تا در صورت مشکل، بازگشت سریع باشد. اگر روی سرور مقصد سرویس‌های وابسته به systemd دارید، ترتیب راه‌اندازی را در فایل unit در systemd: بخش‌ها، ری‌استارت و وابستگی بررسی کنید تا بعد از تغییر DNS سرویس‌ها به‌درستی بالا بیایند.

اگر می‌خواهید انتقال را روی یک محیط تازه و کنترل‌شده انجام دهید، یک هاست لینوکس مقصد مناسب می‌تواند نقطهٔ شروع باشد. اما مهم‌ترین کاری که باید همین امروز انجام دهید این است: قبل از هر انتقال بزرگ، یک بار با --dry-run اجرا کنید و خروجی را بخوانید. این پنج ثانیه، جلوی ساعت‌ها دردسر را می‌گیرد.

آیا این مطلب برایتان مفید بود؟