کپیکردن بخشِ آسان است — چیزی که واقعاً باعثِ قطعی میشود
از کسی بپرسید مهاجرتش چقدر طول میکشد، و او تخمینِ انتقال را میگوید. دویست گیگابایت روی یک لینکِ گیگابیتی، بگویید چهل دقیقه، یک ساعت هم برای اطمینان اضافه کنید. آن عدد معمولاً درست است و تقریباً هیچوقت عددی نیست که اهمیت دارد، چون انتقال درحالی رخ میدهد که سرورِ قدیمی هنوز به درخواستها پاسخ میدهد. هیچکس در طولِ کپیکردن قطعی را تجربه نمیکند. قطعی در فاصلهٔ بینِ ماشینِ جدید درست است و اینترنت هم همین را میگوید رخ میدهد، و طولِ آن فاصله را کشهایی تعیین میکنند که کنترلشان دستِ شما نیست.
چهار حالتِ شکست مسئولِ بیشترِ قطعیهای واقعیِ مهاجرتاند، و هیچکدامشان پهنایباند نیست. یک رکوردِ DNS که time-to-live اش هنگامِ تغییردادن هنوز یک روز بوده، پس بخشِ قابلتوجهی از دنیا همچنان به ماشینی وصل میشود که از قبل خاموشش کردهاید. پایگاهدادهای که بعد از گرفتنِ dump از آن نوشتن پذیرفته، پس میزبانِ جدید زندگیاش را با یک نسخهٔ بیسروصدا کهنه شروع میکند و شما فقط از شکایتِ یک مشتری میفهمید کدام بیست دقیقه کم است. یک گواهیِ TLS و کلیدِ حسابِ ACME اش که فقط روی دیسکِ قدیمی وجود داشته، پس میزبانِ جدید برای هر مرورگری یک نامِ ناهمخوان سرو میکند. و یک یکپارچهسازیِ خروجی — یک پردازشگرِ پرداخت، یک دراپِ SFTP بانکی، یک API شریک، یک پایگاهداده روی یک ارائهدهندهٔ سوم — که با آدرسِ IP allowlist شده، و درست در دورترین نقطهٔ ممکن از تغییری که باعثش شده، بیسروصدا شکست میخورد.
ارزش دارد دربارهٔ عبارتی که همه به کار میبرند صریح باشیم. «مهاجرتِ بدون قطعی» تقریباً همیشه یعنی چند ثانیه اتصالِ ردشده که هیچ انسانی متوجهش نشده، و این هدفی کاملاً خوب برای نشانهگیری است. صفرِ واقعی نیازمندِ این است که هر دو ماشین همزمان درست سرویس بدهند، که خودش نیازمندِ اپلیکیشنی است که تحملِ دو-ماشینبودن را داشته باشد: بدون وضعیتِ نشستِ محلی، بدون دایرکتوریِ آپلودِ محلی که فقط یک طرف داردش، و پایگاهدادهای که یا replicate میشود یا جای کاملاً دیگری زندگی میکند. بیشترِ استکهای self-hosted به آن استاندارد نمیرسند، و برنامهٔ صادقانه یک توقفِ کوتاه، کنترلشده و تمرینشده است، نه یک پروژهٔ معماری که قصدِ شروعش را نداشتید.
پس شکلِ یک مهاجرتِ خوب زیرکانه نیست. ماشینِ جدید را زود بسازید و درحالیکه قدیمی بارِ کاری را حمل میکند، اثبات کنید که کار میکند. بخشِ غیرقابلبازگشت را به چند دقیقه دستورِ اسکریپتشده کوچک کنید. هر بار فقط یک چیز را تغییر دهید. و توانِ برگشتن را نگه دارید، با تاریخی که در آن دیگر بابتش هزینه نمیدهید.
فهرستبرداری: بخشهایی از سرور که در مخزنِ شما نیستند
مخزنِ دیپلویِ شما اپلیکیشن را توصیف میکند. ماشین را توصیف نمیکند. یکجایی بینِ اولین apt install و امروز، سرور لایهای انباشته میکند که هیچ کنترلِ نسخهای هرگز آن را ندیده: بستههایی که دستی برای رفعِ یک مشکل نصب شدهاند، یک واحدِ systemd که کسی با عجله نوشته، یک کارِ cron زیرِ یک حسابِ سرویس، قوانینِ فایروال، تنظیماتِ sysctl، یک locale، یک منطقهٔ زمانی، یک فایلِ swap، گواهیهای TLS، کلیدهای میزبانِ SSH، نقشها و مجوزهای پایگاهداده، و یک دایرکتوریِ رسانه که دقیقاً به این دلیل در مخزن نیست که کاربران آنجا گذاشتهاندش. مهاجرتدادن یعنی بازتولیدِ عامدانهٔ آن لایه، و تنها راهِ عامدانه انجامدادنش این است که اول آن را یادداشت کنید.
پنج دستور بیشترِ آن را ثبت میکنند. dpkg --get-selections روی Debian و Ubuntu، یا dnf repoquery --userinstalled روی Rocky و Alma، مجموعهٔ بستهها را به شما میدهد. systemctl list-unit-files --state=enabled هر چیزی را که برای اجرا در زمانِ بوت پیکربندی شده به شما میدهد، که پرسشِ بهتری از «چه چیزی در حالِ اجراست» است، چون چیزی را هم که الان کرش کرده شامل میشود. crontab -l -u برای هر حساب در /etc/passwd، بههمراه محتوای /etc/cron.d و هر واحدِ .timer، کارِ زمانبندیشده را به شما میدهد. nft list ruleset یا ufw status numbered فایروال را به شما میدهد. و ss -tulpn چیزی را که واقعاً در حالِ گوشدادن است به شما میدهد، که اینطوری سرویسی را که فراموش کرده بودید وجود دارد کشف میکنید. هر پنجتا را در فایل بنویسید و از روی ماشین کپیشان کنید بیرون، نه رویش.
بعد فهرستی هست که هیچکس یادداشتش نمیکند، و همان است که هفتهها بعد نیش میزند: هر چیزی، هر جایی، که به آدرسِ IP فعلیِ شما اعتماد میکند. دروازههای پرداخت با allowlistهای IP. یک پایگاهدادهٔ managed روی یک ارائهدهندهٔ دیگر که قوانینِ دسترسیاش آدرسِ قدیمی را نام میبرد. یک relay ی SMTP که بر اساسِ شبکه احراز هویت میکند. یک سرویسِ مانیتورینگ، یک فرستندهٔ webhook که فقط به آدرسهای شناختهشده پست میکند، فایروالِ یک همکار. پیکربندی و مستنداتِ خودتان را برای آدرسِ قدیمی grep کنید، بعد پنلِ کنترلِ هر سرویسِ شخصِثالثی را که پولش را میدهید بررسی کنید. اینها بعد از گذار، ناهمزمان، در هر لحظهای که یکپارچهسازی بعداً اجرا شود میشکنند — و دقیقاً به همین دلیل است که اینقدر زیاد بهعنوانِ «همزمان یک چیزِ دیگر هم خراب شد» تشخیص داده میشوند.
در نهایت، خودِ ناحیهٔ DNS را هم ثبت کنید. آن را export کنید، یا دستِکم نوع، مقدار و TTLِ هر رکورد را یادداشت کنید، چون مهاجرت دقیقاً همان لحظهای است که یک نفر متوجهِ رکوردی میشود که دو سال اشتباه بوده و از سرِ لطف، وسطِ همهچیزِ دیگر درستش میکند.
| چه چیزی را فهرستبرداری کنید | کجا زندگی میکند | اگر فراموشش کنید چه چیزی میشکند |
|---|---|---|
| بستههای نصبشده بهصورت دستی | پایگاهدادهٔ بستهها | یک سرویس روی میزبانِ جدید بهخاطرِ یک کتابخانهٔ گمشده که هیچکس افزودنش را بهیاد ندارد، از شروع سر باز میزند. |
| واحدها و تایمرهای فعالشده | systemd | کارِ پسزمینه بیسروصدا متوقف میشود: بدون پشتیبانگیری، بدون تمدیدِ گواهی، بدون کارگرِ صف. |
| کارهای cron بهازای هر کاربر | crontabهای هر حساب | کارهای شبانه ناپدید میشوند و در پایانِ ماه متوجهشان میشوید. |
| مجموعهقوانینِ فایروال | nftables یا ufw | یا یک پورت بسته میماند و اپ خراب بهنظر میرسد، یا همهچیز باز است. |
| گواهیهای TLS و کلیدِ حسابِ ACME | دایرکتوریِ گواهی | مرورگرها یک ناهمخوانیِ نام نشان میدهند، و تمدیدها یک حسابِ تازه شروع میکنند. |
| نقشها و مجوزهای پایگاهداده | تنظیماتِ سراسریِ سرور، نه dump | داده بهخوبی بازیابی میشود اما اپلیکیشن نمیتواند واردش شود. |
| allowlistهای IP شخصِثالث | پنلهای افرادِ دیگر | پرداختها، webhookها و APIهای شریک ساعتها یا روزها بعد شکست میخورند. |
| ناحیهٔ DNS با TTLها | ارائهدهندهٔ DNS شما | نمیتوانید بگویید کدام رکوردها هنوز باید جابهجا شوند، یا چقدر کش شدهاند. |
اول TTLِ DNS را پایین بیاورید — و بفهمید چرا باید روزها زودتر این کار را کرد
یک resolver بازگشتی، پاسخ را برای همان time-to-live ی که دریافت کرده کش میکند، و هیچ الزامی ندارد پیش از انقضای آن دوباره بپرسد. این پیامدی دارد که تقریباً همه را بارِ اول گیر میاندازد: پایینآوردنِ TTLِ یک رکورد از 86400 به 300 برای resolver ای که پاسخِ قدیمی را ده دقیقه پیش کش کرده، مطلقاً هیچ کاری نمیکند. آن resolver پاسخِ یکروزه را برای بیستوسه ساعت و پنجاه دقیقهٔ دیگر نگه میدارد، و فقط بعد از آن از TTLِ پنجدقیقهایِ جدیدِ شما باخبر میشود. پس TTLِ پایین باید دستِکم یک TTLِ کاملِ قدیمی پیشتر منتشر شود، پیش از اینکه قصدِ جابهجاییِ چیزی را داشته باشید. اگر رکوردهای شما روی TTLِ یکروزهاند، اولین اقدامِ مهاجرت دو روز پیش از گذار رخ میدهد، و فقط یک تغییرِ یکخطی است.
این کار را برای هر رکوردی که به ماشین اشاره میکند انجام دهید، نه فقط همانی که در ذهن دارید. رکوردِ A و رکوردِ AAAA — یک آدرسِ IPv6 که به میزبانِ قدیمی اشارهکردنش باقی مانده یک باگِ بهزیبایی گیجکننده است، چون کلاینتهای dual-stack بیسروصدا آن را ترجیح میدهند و فقط بخشی از کاربرانتان تحتِ تأثیر قرار میگیرند. رکوردهای MX. هر CNAME ای که جلوترشان است — بهیاد داشته باشید که یک کلاینتِ دنبالکنندهٔ یک زنجیره، تابعِ TTLِ تکتکِ حلقههای آن است، پس یک رکوردِ A پنجدقیقهای پشتِ یک CNAME یکروزه هنوز عملاً یک روز است. و اگر همزمان دارید ارائهدهندهٔ DNS را هم عوض میکنید، این کار را در همان هفته انجام ندهید: تفویضِ nameserver و رکوردهای glue توسط ناحیهٔ والد طبقِ زمانبندیِ خودشان کش میشوند، و ترکیبکردنِ این دو تغییر یعنی وقتی چیزی میشکند، نمیفهمید کدامیک باعثش شده.
فرض نکنید، تأیید کنید. dig +noall +answer example.com A نشان میدهد یک resolver الان چه چیزی را نگه داشته و چه شمارشِ معکوسی رویش مانده؛ پرسوجوی مستقیمِ سرورِ authoritative خودتان با dig @ns1.example.net example.com A نشان میدهد واقعاً چه چیزی منتشر کردهاید. اگر این دو با هم توافق نداشتند، دارید به کش نگاه میکنید، و عددِ کنارِ رکورد دقیقاً همان مدتی است که باید صبر کنید.
ارزش دارد بودجهای برای دو ظرافت کنار بگذارید. برخی resolverها clamp میکنند: بخشی از forwarderهای ISP و سازمانی صرفنظر از چیزی که منتشر میکنید یک TTLِ حداقلی را اجرا میکنند، که از نظرِ فنی نکوهیده اما کاملاً واقعی است. و طبقِ RFC 8767، یک resolver ممکن است وقتی نمیتواند به سرورهای authoritative شما برسد، عمداً یک پاسخِ کهنه سرو کند — رفتاری عالی برای تابآوری، اما همان روزی که میخواهید یک تغییر منتشر شود آزاردهنده است. رویِهمرفته، برای یک دُمِ بلند که با ساعت، گاهی یک روز، اندازهگیری میشود، پس از جابهجاییِ بیشترِ ترافیک برنامهریزی کنید. آن دُم مشکلی نیست تا وقتی ماشینِ قدیمی همچنان درست پاسخ میدهد، که دقیقاً به همین دلیل روشن نگهش میدارید. RFC 2181 مرجعِ این است که TTLها وقتی پیادهسازیها با هم توافق ندارند باید چطور رفتار کنند.
| چه زمانی | اقدام | چرا همان زمان |
|---|---|---|
| T منهای 7 روز | فهرستبرداری از سرورِ قدیمی؛ نوشتنِ runbook | هر چیزی که اینجا پیدا میشود برنامه را تغییر میدهد، پس باید پیش از قطعیشدنِ برنامه رخ دهد. |
| T منهای 3 روز | تأمینِ VPS جدید؛ اولین بازیابی؛ تمرین | وقت باقی میگذارد تا وقتی تمرین شکافهایی پیدا کرد، ماشین بارِ دوم بازسازی شود. |
| T منهای 2 روز | پایینآوردنِ TTLهای A، AAAA و MX به 300 | باید یک TTLِ کاملِ قدیمی بگذرد تا مقدارِ پایین در همهٔ کشها بنشیند. |
| T منهای 1 روز | اولین پاسِ rsync؛ شروعِ replication پایگاهداده | طولانی و بدونِ نظارت، درحالیکه سرورِ قدیمی هنوز ترافیکِ تولید را حمل میکند. |
| T صفر | توقفِ نوشتنها، sync نهایی، تأیید، تعویضِ DNS | تنها پنجرهٔ غیرقابلبازگشت؛ کوتاه است چون همهٔ موارد بالا از قبل رخ دادهاند. |
| T بهعلاوهٔ 1 ساعت | هر دو لاگِ دسترسی را تماشا کنید | افتِ ترافیک روی میزبانِ قدیمی، اندازهگیریِ واقعیِ شما از انقضای کش است. |
| T بهعلاوهٔ 7 روز | از رده خارجکردنِ میزبانِ قدیمی؛ بالابردنِ دوبارهٔ TTLها | بازگشت منقضی شده؛ یک TTLِ دائمیِ 300 ثانیهای بدونِ هیچ سودی، فقط تأخیر هزینه میکند. |
روی جعبهٔ جدید تمرین کنید درحالیکه قدیمی هنوز سرویس میدهد
باارزشترین عادت در کلِ این فرایند این است که ماشینِ جدید روزها پیش از اینکه اهمیت پیدا کند وجود دارد و کار میکند. یک VPS از نظرِ عملی یک اجارهٔ ساعتی است: روی پلنهای ما یک سرور تقریباً شصت ثانیه بعد از تأییدِ پرداخت زنده میشود، بدون هزینهٔ راهاندازی و بدون قرارداد، پس یک تمرینِ سهروزه روی یک پلنِ $8.50 چیزی حدودِ یک دلار هزینه دارد. این راهی بهطرزِ چشمگیری ارزان برای تبدیلِ هر مجهولِ مهاجرتتان به یک معلوم، پیش از آنکه ساعت شروع به شمردن کند.
آن را با hostname تست کنید، نه با IP. مرور به آدرسِ سرورِ جدید، virtual host پیشفرض، بدون تطبیقِ SNI، یک هشدارِ گواهی و مجموعهمسیرهایی میدهد که ممکن است اصلاً شبیهِ production نباشند — و با کمالِ میل شما را متقاعد میکند چیزی کار میکند درحالیکه نمیکند. ابزارِ درست یک override برای resolver است. curl --resolve یک hostname را برای یک دستور به یک آدرس سنجاق میکند، پس curl --resolve example.com:443:203.0.113.10 https://example.com/ نامِ واقعی، دستدهیِ واقعیِ TLS و virtual host واقعی را روی ماشینِ جدید به کار میگیرد درحالیکه بقیهٔ دنیا هنوز به قدیمی میرسد. برای تستِ تعاملی، یک خط در فایلِ hosts ایستگاهِ کاریِ شما همان کار را برای یک مرورگر انجام میدهد.
چیزی که تمرین بهطورِ قابلاعتماد گیر میاندازد، همان لایهٔ مستندنشدهٔ انباشتهشده از بخشِ قبل است. دیمنی که از پیش از آخرین ریبوت در حالِ اجرا بوده و در واقع فعال نیست. کارِ cron ای که برای گزارشِ شکستها به یک transport ایمیلِ محلی وابسته است. مالکیتِ فایلی که بهصورتِ عدد از کپی جان سالم بهدر برده اما روی ماشینی با /etc/passwd ای متفاوت معنیِ دیگری دارد. یک آدرسِ hardcode شده در یک فایلِ پیکربندی. پایگاهدادهای که با یک character set روی نسخهای ساخته شده که پیشفرضش فرق داشته. یک نسخهٔ فرعیِ Python یا PHP که چیزی را که استفاده میکنید deprecated کرده. تعمیرِ هرکدام از اینها در طولِ تمرین ده دقیقه هزینه دارد و تشخیصش در طولِ گذار یک ساعت.
یک تست بیشتر از بقیه ارزش دارد: ماشینِ جدید را دوبار بسازید. آن را از صفر، فقط با استفاده از فهرست و پشتیبانتان، بدونِ نگاهکردن به سرورِ قدیمی، بازسازی کنید. اگر بارِ دوم درست بالا آمد، فهرستتان واقعی است و runbook تان قابلِاجراست. اگر نیامد، همین الان شکاف را در موقعیتی پیدا کردهاید که پیداکردنش هیچ هزینهای ندارد. وقتی درست شد یک اسنپشات بگیرید — اسنپشاتهای ساعتی با نگهداریِ هفتروزه روی هر پلن گنجانده شدهاند، و بازیابی تقریباً سی ثانیه طول میکشد — تا هر آزمایشِ بعدی روی جعبهٔ جدید هم قابلِبازگشت باشد.
دوبار rsync: یک پاسِ طولانی درحالیکه در حالِ اجراست، یک پاسِ کوتاه در پنجره
الگوی دو-پاس همان چیزی است که پنجرهٔ نگهداری را کوتاه نگه میدارد. پاسِ اول درحالیکه سرویس کاملاً زنده است اجرا میشود و میتواند هرقدر لازم باشد طول بکشد — ساعتها، یک شب کامل، در طولِ یک آخرِ هفته. پاسِ دوم در طولِ توقف اجرا میشود و فقط چیزی را منتقل میکند که از پاسِ اول به بعد تغییر کرده، که روی یک بارِ کاریِ عادی بخشِ کوچکی از داده و تعدادِ قابلپیشبینیای دقیقه است. دارید یک کپیِ طولانیِ بدونِ نظارت را با یک کپیِ کوتاهِ زیرِ نظارت معاوضه میکنید، و این معاوضه تقریباً همیشه ارزشش را دارد.
فلگها بیشتر از آنچه مردم انتظار دارند اهمیت دارند. rsync -aHAX --numeric-ids خطِ پایه است: -a برای حالتِ archive، -H برای حفظِ hardlinkها — که برای ذخیرهسازیهای Maildir و درختهای پشتیبانِ deduplicate شده بهشدت اهمیت دارد، چون حذفشان میتواند مصرفِ دیسکتان را چندبرابر کند — -A برای ACLهای POSIX، -X برای صفتهای گسترده مثلِ برچسبهای SELinux و قابلیتهای فایل، و --numeric-ids تا شناسهٔ کاربری بهجای اینکه از پایگاهدادهٔ کاربریِ مبدأ resolve و دوباره روی یک پایگاهدادهٔ متفاوت در مقصد resolve شود، بهصورتِ عدد کپی شود. برای یک خطِ پیشرفتِ معقول --info=progress2 را اضافه کنید و --partial را هم، تا انتقالِ قطعشده بهجای شروعِ دوباره، از همانجا ادامه یابد. -z را نگذارید مگر اینکه لینک واقعاً کند باشد: فشردهکردنِ رسانههای ازقبلفشرده و آرشیوهای رمزنگاریشده فقط گلوگاه را به CPU منتقل میکند.
--delete را فقط در پاسِ دوم استفاده کنید. در پاسِ اول یک footgun بدون هیچ سودی است، چون چیزی روی مقصد نیست که نیاز به حذف داشته باشد. در پاسِ دوم ضروری است: بدونش، فایلی که بینِ دو پاس روی سرورِ قدیمی حذف کردهاید برای همیشه روی سرورِ جدید زنده میماند، و اینطوری یک مهاجرت به سروکردنِ محتوایی ختم میشود که عمداً حذف شده بود.
کاری که نباید بکنید rsync کردنِ کلِ فایلسیستمِ root است. این یک میانبُرِ محبوب است و ماشینی تولید میکند که هیچکس نمیتواند دربارهاش استدلال کند. حتی با excludeکردنِ /proc، /sys، /dev، /run و /tmp، به سیستمی میرسید که کرنل و initramfs اش از یک میزبان آمده، نامگذاریِ اینترفیسِ شبکهاش از سختافزاری متفاوت مشتق شده، /etc/machine-id اش حالا روی دو ماشینِ زنده تکراری شده، و پنج سالِ انباشتهشدهٔ drift پیکربندیاش را همین الان پول دادهاید حفظش کنید. داده و پیکربندیای را که فهرستبرداری کردهاید مهاجرت دهید؛ سیستمعامل را تازه از یک template نصب کنید. یک ساعتِ اضافه میگیرد، یک پایهٔ مدرن و تمیز به شما میدهد، و یعنی سرورِ جدید ماشینی است که میفهمیدش، نه کپیِ ماشینی که نمیفهمیدش.
بهجای اعتمادکردن به exit code، خودِ کپی را تأیید کنید. بعد از هر دو پاس، همان دستور را دوباره با -n --checksum --itemize-changes اجرا کنید: یک dry run که محتوا را بهجای timestamp مقایسه میکند و بهازای هر تفاوت یک خط چاپ میکند. سکوت همان نتیجهای است که میخواهید، و ادعایی بهمراتب قویتر از یکسانبودنِ du -s روی هر دو طرف است.
پایگاهداده همان بخشی است که rsync نمیتواند در آن کمکتان کند
کپیکردنِ دایرکتوریِ یک پایگاهدادهٔ زنده در سطحِ فایل، یک کپیِ پارهشده به شما میدهد: بعضی صفحهها نوشته شده، بعضی نه، بدونِ هیچ تضمینی که کدامبخشش یک مرزِ تراکنشیِ سازگار میسازد. InnoDB ممکن است کاملاً از پسش بربیاید و سالم بهنظر برسد، که این از شکستخوردن هم بدتر است، چون فقط روزی میفهمید که بازیابی کار نمیکند. دقیقاً دو استراتژیِ صادقانه وجود دارد — گرفتنِ یک dump سازگار از نظرِ تراکنشی، یا replicateکردن — و انتخاب بینِ آن دو، انتخابی است دربارهٔ اینکه چقدر قطعی میخرید.
برای مسیرِ dump روی MySQL و MariaDB، mysqldump --single-transaction --routines --triggers --events بدونِ قفلکردنِ کلِ سرور یک snapshot سازگار میدهد، با دو نکتهٔ هشدارآمیز که ارزشِ دانستن دارند: فقط برای جدولهای تراکنشی سازگار است، پس یک جدولِ قدیمیِ MyISAM بهتنهایی بیسروصدا این تضمین را میشکند، و هر عبارتِ DDL ای که در طولِ dump اجرا شود هم همین کار را میکند. روی PostgreSQL، pg_dump -Fc هر پایگاهداده را مدیریت میکند، و pg_dumpall --globals-only همان نیمهای را مدیریت میکند که مردم فراموشش میکنند — نقشها، رمزهای عبور، مجوزها و tablespaceها در سطحِ cluster زندگی میکنند، نه داخلِ یک پایگاهدادهٔ تکی، پس بازیابی بدونِ آنها دادهای بینقص تولید میکند که اپلیکیشن نمیتواند به آن احراز هویت کند.
عددی که پنجرهٔ شما را تعیین میکند اندازهٔ dump نیست، بلکه dump بهعلاوهٔ انتقال بهعلاوهٔ بازیابی بهعلاوهٔ بازسازیِ index است، و آخری معمولاً بزرگترین است. آن را در طولِ تمرین روی dataset واقعی اندازه بگیرید، نه اینکه تخمین بزنید. چند گیگابایت یعنی چند دقیقه؛ صد گیگابایت با indexگذاریِ قابلتوجه میتواند ساعتها شود، و در آن نقطه مسیرِ dump برای یک سرویسِ زنده دیگر عملی نیست و replication پاسخ است، نه یک بهینهسازی.
مسیرِ replication هزینه را وارونه میکند: کار را از قبل انجام میدهید و گذار پیشپاافتاده میشود. روزها زودتر یک replica روی میزبانِ جدید راه بیندازید — replication مبتنیبر GTID برای MySQL و MariaDB، pg_basebackup و یک standby استریمینگ برای PostgreSQL، یا logical replication وقتی همزمان دارید از یک نسخهٔ اصلی هم عبور میکنید. بگذارید بهروز برسد و بهروز بماند. گذار آنوقت این است: نوشتن روی primary را متوقف کنید، صبر کنید تا replica صفر تأخیر گزارش کند، آن را promote کنید، اپلیکیشن را بهسمتش بگردانید. این چند ثانیه است، و تنها روشی است که صادقانه شایستهٔ عبارتِ «قطعیِ نزدیکبهصفر» است.
وضعیتی را که در پایگاهداده نیست فراموش نکنید. Redis، Valkey و Memcached نشستها، شمارندههای rate-limit و صفها را نگه میدارند؛ یک search index در Elasticsearch، OpenSearch یا Meilisearch یک نسخهٔ مشتقشده از دادهتان را نگه میدارد. برای هرکدام، صریحاً تصمیم بگیرید آیا مهاجرتش میدهید یا بازسازیش میکنید. یک نمونهٔ Redis که نشستها را نگه داشته، ارزشِ جابهجایی با یک BGSAVE و یک کپی از فایلِ حاصل را دارد، مگر اینکه راضی باشید همه را از سیستم خارج کنید. یک search index تقریباً همیشه reindexکردنش روی میزبانِ جدید سریعتر از انتقالدادنش است — اما reindexکردن زمان میبرد، پس آن را در طولِ تمرین شروع کنید، نه در طولِ توقف.
| استراتژی | قطعیِ گذار | کار پیش از پنجره | چه زمانی انتخابِ درستی است |
|---|---|---|---|
| کپیِ فایلیِ یک دایرکتوریِ دادهٔ در حالِ اجرا | هیچ، و ممکن است داده خراب باشد | هیچ | هرگز. اینجا آورده شده چون اولین چیزی است که مردم امتحان میکنند. |
| dump و بازیابیِ سازگار | dump بهعلاوهٔ انتقال بهعلاوهٔ بازیابی بهعلاوهٔ reindex | یکبار در طولِ تمرین اندازهگیری کنید | Dataset هایی بهاندازهٔ کافی کوچک که مجموعِ اندازهگیریشده در تحملِ شما جا بگیرد. |
| dump، بازیابی، سپس بازپخشِ delta | دقیقهها | نگهداریِ binlog یا WAL از قبل پیکربندیشده | Datasetهای میاناندازه که یک replica کامل بیش از چیزی است که میخواهید راه بیندازید. |
| replica ای که در گذار promote میشود | ثانیهها | replication در حالِ اجرا و بدونِ تأخیر برای چند روز | هر چیزِ بزرگ، و هر چیزی که یک توقفِ طولانی در آن غیرقابلقبول است. |
| پایگاهداده را متوقف کنید، فایلها را سرد کپی کنید | طولِ خودِ کپی | هیچ | سرویسهای داخلیِ کوچک که یک ساعت آفلاینبودن واقعاً هیچ هزینهای ندارد. |
گواهیهای TLS، کلیدهای میزبانِ SSH و هویتهایی که نمیتوانید فقط دوباره صادرشان کنید
صدورِ گواهی دقیقاً در بدترین لحظهٔ ممکن یک مسئلهٔ مرغوتخممرغ دارد. چالشِ HTTP-01 کنترلِ یک نام را با گرفتنِ یک فایل از روی همان نام اثبات میکند، که نیازمندِ این است که نام از قبل به ماشینِ در حالِ اعتبارسنجی resolve شود — و پیش از گذار، نمیشود. سه راهِ خروج هست و باید عامدانه یکی را انتخاب کنید. دایرکتوریِ گواهی را آنطرف کپی کنید، که بلافاصله کار میکند و چون کلیدِ خودتان است کاملاً مشروع است. بهجایش از چالشِ DNS-01 استفاده کنید، که با انتشارِ یک رکوردِ TXT اعتبارسنجی میکند و به همین دلیل روی ماشینی هم که هنوز چیزی بهسمتش اشاره نمیکند کار میکند، و بههرحال تنها گزینه برای یک گواهیِ wildcard است. یا یک پنجرهٔ کوتاه بعد از تعویضِ DNS را بپذیرید که در طولِ آن میزبانِ جدید گواهیِ خودش را درخواست میکند، که برای یک سایتِ شخصی خوب است و برای هر چیزی که کاربر دارد خوب نیست.
اگر کپی میکنید، کلِ آن را کپی کنید. گواهیها و کلیدهای خصوصی بخشِ بدیهیاند؛ کلیدِ حسابِ ACME همان بخشی است که جا میماند، و بدونش، کلاینتِ روی میزبانِ جدید در اولین تمدید یک حسابِ کاملاً تازه ثبت میکند. همهچیز بهنظر کار میکند، و شما بیسروصدا تاریخچهٔ حساب و هر وضعیتِ مختصِ آن حساب را از دست دادهاید. مالکیت و مجوزها را هم حفظ کنید — کلیدهای خصوصی روی 600، دایرکتوریِ آرشیو روی 700 — چون کپیای که مجوزهای یک کلید را گستردهتر کند، نتیجهاش از خودِ مهاجرتی که نگرانش بودید هم بدتر است.
برنامهریزی نکنید که بارها دوباره صادر کنید و ببینید چه میشود. محدودیتهای نرخِ Let's Encrypt گواهیهای تکراری برای یک مجموعهٔ یکسان از hostnameها را در هفته سقف میزنند، و دو تمرینِ ناموفق بهعلاوهٔ یک صدورِ واقعی، راهی بهطرزِ شگفتآوری آسان برای رسیدن به سقف است، درست همان روزی که نمیتوانید صبر کنید. تمرینها را بهسمتِ محیطِ staging بگردانید؛ endpoint تولید را برای کارِ واقعی نگه دارید.
کلیدهای میزبانِ SSH آن هویتِ دیگرِ درگیر در بازیاند، و اینجا پاسخِ درست واقعاً به این بستگی دارد که چرا دارید جابهجا میشوید. کپیکردنِ /etc/ssh/ssh_host_* مهاجرت را نامرئی میکند: known_hosts ی هر کلاینت همچنان تطبیق دارد، و هیچ اتوماسیونی با یک هشدارِ fingerprint متوقف نمیشود. این راحت است، و برای یک جابهجاییِ روتین بینِ ارائهدهندههایی که به آنها اعتماد دارید انتخابِ درستی است. اگر دلیلِ ترککردنتان این است که دیگر به میزبان یا ارائهدهندهٔ قدیمی اعتماد ندارید، انتخابِ اشتباهی است — هرکس که به آن دیسک دسترسی داشته کلیدِ خصوصیِ میزبانِ شما را هم داشته، و بردنش به سرورِ جدید یعنی بردنِ همان مشکل به همراهش. در آن حالت کلیدهای تازه بسازید، fingerprint جدید را از کانالی که خودِ سرور نیست منتشر کنید، و از کلاینتها بخواهید ssh-keygen -R را روی ورودیِ قدیمی اجرا کنند. برای اینکه کلیدها کجا زندگی میکنند و چطور انتخاب میشوند، مرجعِ sshd در OpenSSH را ببینید.
یک قانون در هر دو حالت مطلق است: هرگز هر دو ماشین را همزمان با کلیدِ میزبانِ یکسان و نامِ میزبانِ یکسانی که به هر دو resolve میشود اجرا نکنید. این پیکربندیای است که در آن یک کلاینت نمیتواند بفهمد به کدام سرور رسیده، که دقیقاً همان ویژگیای است که کلیدهای میزبان برای جلوگیری از آن وجود دارند. در طولِ پنجرهٔ همپوشانی، یا میزبانِ قدیمی هویتِ خودش را نگه میدارد و جدیدی هویتِ خودش را دارد، یا نامِ میزبانِ قدیمی درست همان لحظهای بازنشسته میشود که جدیدی کلیدش را میگیرد.
گذار: ده دقیقهای که به یک دستورِ مکتوب نیاز دارد
تا اینجا همهچیز قابلِبازگشت و بدونِ عجله بود. گذار هیچکدام از این دو نیست، و دقیقاً همین کلِ استدلال برای ازپیشنوشتنش است: بداههسازی زیرِ فشارِ زمان همان چیزی است که یک پنجرهٔ پنجدقیقهای را به یک حادثهٔ دوساعته تبدیل میکند. runbook باید دستوراتِ عینی و بهترتیب باشد، با خروجیِ موردِ انتظار کنارِ هرکدام، طوری که اجرایش نیازمندِ خواندن باشد، نه فکرکردن.
ترتیبی که کار میکند. اول، نوشتن روی میزبانِ قدیمی را متوقف کنید — یک صفحهٔ تعمیر و نگهداری، یک فلگِ read-only، یا بهسادگی متوقفکردنِ اپلیکیشن درحالیکه وبسرور همچنان با یک صفحهٔ نگهدارنده پاسخ میدهد. دوم، پاسِ نهاییِ rsync را با --delete اجرا کنید. سوم، مرحلهٔ پایگاهداده را تمام کنید: یا همان dump-انتقال-بازیابیِ اندازهگیریشده، یا نوشتن روی primary را متوقف کنید، صفربودنِ تأخیرِ replication را تأیید کنید و replica را promote کنید. چهارم، سرویسها را روی میزبانِ جدید شروع کنید و کمی مهلت بدهید تا جا بیفتند — connection poolها، کارگرهای صف و بارگذاریِ گواهی، همه روی یک شروعِ سرد بیش از آنچه بهیاد دارید طول میکشند. پنجم، تأیید کنید. ششم، و فقط بعد از عبورِ تأیید، رکوردهای DNS را تغییر دهید. هفتم، میزبانِ قدیمی را روشن بگذارید.
تأیید باید معنایی داشته باشد. گرفتنِ صفحهٔ اصلی فقط ثابت میکند وبسرور روشن است و نه چیزِ دیگری. از curl --resolve روی hostname واقعی، روی مسیری که پایگاهداده را لمس میکند و چیزی برمیگرداند که بتوانید رویش assert کنید استفاده کنید — یک health endpoint که اتصالِ پایگاهداده، اتصالِ کش و فضای آزادِ دیسک را چک میکند فقط به همین دلیل ارزشِ نوشتن دارد. بعد لاگِ دسترسیِ میزبانِ جدید را بخوانید و تأیید کنید درخواستتان در آن هست. این قدمِ آخر شاید عجیبغریب بهنظر برسد، اما همان قدمی است که موقعیتی را میگیرد که override ی resolver شما اثر نکرده و شما فقط با دقت سرورِ قدیمی را تأیید کردهاید.
بعد از تعویضِ DNS، هر دو لاگِ دسترسی را کنارِ هم تماشا کنید. ترافیک روی میزبانِ جدید بالا میرود؛ ترافیک روی میزبانِ قدیمی با انقضای کشها افت میکند، و آن منحنیِ افت تنها اندازهگیریِ صادقانه از این است که دُم واقعاً چقدر طول میکشد. وقتی لاگِ میزبانِ قدیمی نزدیکِ صفر تخت شد، مهاجرت تمام شده. تا وقتی این اتفاق نیفتاده، ماشینِ قدیمی باید برای کاربرانی که هنوز به آن میرسند درست رفتار کند — و دقیقاً به همین دلیل روشن و read-only میماند، نه اینکه در یک لحظهٔ شوروشوق خاموش شود. اگر اپلیکیشن نمیتواند read-only شود، معمولاً سروکردنِ دادهٔ کهنه توسط میزبانِ قدیمی برای چند ساعت آسیبِ کوچکتری است تا سروکردنِ connection refused توسط میزبانِ قدیمی، اما این قضاوتی است که باید از قبل بگیرید، نه در همان لحظه.
فقط یک چیز را تغییر دهید. نه نسخهٔ اصلیِ سیستمعامل و میزبان را با هم. نه ارائهدهندهٔ DNS و رکوردها را با هم. نه نسخهٔ PHP و ماشین را با هم. هر تغییرِ همزمان، فرضیههایی را که مجبورید ساعتِ سه صبح، وقتی چیزی بدرفتاری میکند، تست کنید چندبرابر میکند، و آن ارتقایی که وسوسه شده بودید همراهش کنید، هفتهٔ بعد هم همانجا هست، روی ماشینی که حالا میتوانید به آن بازگردید.
ایمیل، rDNS و اعتباری که همراهتان سفر نمیکند
اگر سرور ایمیل میفرستد، مهاجرت یک نیمهٔ دوم دارد که هیچ ربطی به خودِ مهاجرت ندارد. یک آدرسِ IP یک اعتبارِ ارسال حمل میکند، آن اعتبار در طولِ هفتهها ساخته میشود، و همراهِ شما نمیآید. این رایجترین راهی است که یک مهاجرتِ از نظرِ فنی بینقص، یک هفته شکایتِ کاربر تولید میکند، و همهٔ اقداماتِ کاهشی باید پیش از گذار شروع شوند، نه بعدش.
اولین رکوردی که میشکند SPF است. یک سیاست شاملِ یک مکانیزمِ ip4: که آدرسِ قدیمی را نام میبرد، همان لحظهای که از آدرسِ جدید ارسال میکنید شروع به شکستخوردن میکند، و چون سیاستهای RFC 7208 رکوردهای DNS هستند، TTLِ خودشان را دارند که باید دورش برنامهریزی کنید. آدرسِ جدید را پیش از گذار به SPF اضافه کنید، در طولِ همپوشانی هر دو را فهرستشده نگه دارید، و وقتی از رده خارجش میکنید قدیمی را حذف کنید. DKIM بدونِ مشکل سفر میکند، تا وقتی کلیدِ خصوصی را همراهِ بقیهٔ پیکربندی کپی کنید، چون نیمهٔ عمومی از قبل منتشر شده. DMARC نیازی به تغییر ندارد، اما ارزش دارد تأیید کنید آدرسِ گزارشدهی هنوز روی ماشینی که در آستانهٔ نابودشدن است وجود دارد.
DNS معکوس برای یک میزبانِ فرستنده اختیاری نیست. رکوردِ PTR روی آدرسِ جدید باید وجود داشته باشد و باید با نامی که سرور در HELO یا EHLO اش اعلام میکند تطبیق داشته باشد، وگرنه سهمِ بزرگی از گیرندهها فقط به همین دلیل رد میکنند. روی پلنهای ما PTR از پنل قابلِویرایش است، پس یک تیکزدن است، نه یک تیکت — آن را در طولِ تمرین تنظیم کنید، تأیید کنید resolve میشود، و تأیید کنید رکوردِ forward هم برمیگردد و تطبیق دارد. بعد پیش از اینکه اصلاً چیزی بفرستید، آدرسِ جدید را در برابرِ فهرستهای سیاهِ اصلی چک کنید: آدرسهای بازیافتی گاهی از قبل لیستشده از راه میرسند، و فهمیدنش از پیامِ تستِ خودتان هیچ هزینهای ندارد درحالیکه فهمیدنش از یک مشتری هزینهٔ زیادی دارد. Spamhaus همانی است که بیشترین اهمیت را دارد.
برای دریافت، هر دو میزبان را دردسترس نگه دارید. سرورِ جدید را بهعنوانِ MX با اولویتِ 10 اضافه کنید و قدیمی را برای یک هفته روی اولویتِ 20 نگه دارید، بهجای اینکه حذفش کنید: فرستندهها دوباره تلاش میکنند، بعضیهایشان رکوردِ MX شما را کش کردهاند، و یک میلسرور که بیسروصدا روی میزبانِ قدیمی میپذیرد، بسیار بهتر از یک bounce است. بعد، پیش از اینکه ماشینِ قدیمی را نابود کنید، صفش را flush و خالی کنید — postqueue -f برای اجبارِ یک تلاشِ تحویل و mailq برای تأییدِ اینکه نتیجه خالی است. پیامهایی که روی صفِ سروری که در آستانهٔ حذفش هستید نشستهاند، تأخیر نخوردهاند. رفتهاند. راهنمای میلسرورِ self-hosted سمتِ deliverability را کامل پوشش میدهد.
وقتی ارائهدهندهٔ قدیمی از قبل ماشین را خاموش کرده
هر مهاجرتی برنامهریزیشده نیست. یک تعلیق بعد از یک شکایتِ سوءاستفاده، کارتی که منقضی شده، حسابی که به دلیلی که هیچکس توضیحش نمیدهد قفل شده — نخِ مشترکشان این است که حالا دارید از ماشینی مهاجرت میکنید که نمیتوانید واردش شوید، و آن ترتیبِ عملیاتِ راحتِ بالا دیگر اعمال نمیشود. ارزش دارد از قبل بدانید معمولاً چه چیزی هنوز ممکن است، چون پنجرهای که در آن ممکن است اغلب کوتاه است.
درحالیکه یک نمونه معلق است اما هنوز حذف نشده، اغلب سه مسیر باقی میماند، بهترتیبِ نزولیِ سودمندی. پنلِ کنترل ممکن است هنوز دانلودِ یک اسنپشات یا پشتیبان را پیشنهاد دهد، که کلِ مسئله را در یک قدم حل میکند. یک حالتِ rescue یا recovery ممکن است هنوز یک ایمیجِ زنده را با دیسکِ شما متصل بوت کند، و به شما اجازه دهد فایلسیستم را mount کنید و چیزهایی که اهمیت دارند را از روی شبکه کپی کنید بیرون. و کنسولِ اضطراری ممکن است حتی وقتی شبکه غیرفعال است هنوز متصل شود، که برای خواندنِ فایلهای پیکربندی، بازیابیِ یک کلید، یا یادداشتکردنِ چیزی که نصب شده بود کافی است — اما مسیری برای پایگاهداده نیست، پس رویش برنامهریزی نکنید. آنها را به همان ترتیب امتحان کنید، و بلافاصله امتحانشان کنید: نگهداری بعد از تعلیق یک سیاست است، نه یک حق، و اغلب با روز اندازهگیری میشود.
محدودیتی هست که هیچ تیکتِ پشتیبانی حلش نمیکند، و ارزش دارد صریح بیانش کنیم چون پیامدِ مستقیمِ همان مدلی است که این سایت میفروشد. روی میزبانی که هرگز هویتی جمعآوری نکرده — از جمله همینجا — هیچ راهی برای اثباتِ اینکه صاحبِ حساب هستید وجود ندارد، جز دراختیارداشتنِ اعتبارنامههای حساب. این همان نکتهٔ هاستینگِ no-KYC است و همان صورتحسابش هم هست: هیچکس نمیتواند دسترسیِ شما را بر اساسِ یک عکسِ پاسپورت بازگرداند، چون هیچ پاسپورتی هرگز به چیزی وصل نبوده. راهنمای هاستینگِ no-KYC این مبادله را کامل پوشش میدهد؛ پیامدِ عملیاتیاش بهسادگی این است که برنامهٔ بازیابیِ شما نمیتواند از خیرخواهیِ کسِ دیگری عبور کند.
توالیِ اضطراری همان توالیِ برنامهریزیشده است با همپوشانیِ حذفشده. میزبانِ جدید را از پشتیبانِ خارجازماشینتان بالا بیاورید. آن را درستوحسابی با hostname تأیید کنید، چون وسوسهٔ ردکردنِ تأیید دقیقاً وقتی قویترین است که از قبل قطعی هستید. بعد بلافاصله DNS را جابهجا کنید — انضباطِ TTL همچنان اعمال میشود، با این تفاوت که حالا دارید دُمِ کش را بهعنوانِ قطعی میپردازید، نه اینکه آن را بهعنوانِ همپوشانی خرج کنید، که این خودش روشنترین استدلال برای پاییننگهداشتنِ TTLها بهعنوانِ یک سیاستِ دائمی است، نه فقط یک قدمِ مهاجرت. برای مدتی منتظرِ ایمیلِ افتکیفیتیافته باشید و زود به مردم هشدار دهید، نه اینکه بعداً توضیح دهید.
این درس فراتر از همین یک روزِ بد هم تعمیم پیدا میکند. پشتیبانی که روی خودِ سرور زندگی میکند پشتیبان نیست؛ یک نسخهٔ دومِ همان چیزی است که در آستانهٔ ازدستدادنش هستید. ویژگیای که اهمیت دارد این است که کپی جای دیگری باشد، پیش از خروج رمزنگاری شده باشد، append-only باشد تا میزبانِ بهخطرافتاده یا معلق نتواند تاریخچهٔ خودش را حذف کند، و — بخشی که همه ردش میکنند — واقعاً یکبار، در یک نمونهٔ یکبارمصرف، بازیابی شده باشد، تا بدانید بازیابی کار میکند. چکلیستِ سختسازی راهاندازیِ آن روی یک ماشینِ جدید را پوشش میدهد؛ اگر این بخش را میخوانید چون از قبل خیلی دیر شده، همین امروز، پیش از هر چیزِ دیگری، آن را روی ماشینی که به آن مهاجرت میکنید راه بیندازید.
بازگشت: trigger را تعریف کنید، و به آن تاریخِ انقضا بدهید
تقریباً همه میگویند یک برنامهٔ بازگشت دارند و تقریباً هیچکس ننوشته چه چیزی trigger اش میکند. بدونِ یک trigger، تصمیم در بدترین لحظه توسطِ هرکسی که خستهتر است گرفته میشود، و نتیجهٔ معمول این است که هیچکس بازنمیگردد چون همیشه حس میشود مشکلِ فعلی پنج دقیقه با حلشدن فاصله دارد. از قبل تصمیم بگیرید: نرخِ خطا بالاتر از یک آستانه برای مدتی، یک عملکردِ خاص که شکسته، یا بهسادگی یک زمانِ مشخص که بعد از آن دیگر دیباگکردن را متوقف میکنید و برمیگردید.
قیدی که اصلاً تعیین میکند بازگشت یعنی چه، نوشتنها هستند. از لحظهای که میزبانِ جدید اولین نوشتنش را میپذیرد، برگشتن یعنی یا دورانداختنِ آن نوشتنها یا بازپخششان روی ماشینِ قدیمی. پس واقعاً بینِ دو محصولِ متفاوت انتخاب میکنید. بازگشتی که پیش از اولین نوشتن گرفته شود، یک تغییرِ DNS است و چند دقیقه طول میکشد. بازگشتی که بعد از یک روز ترافیکِ تولید گرفته شود، یک مهاجرت در جهتِ مخالف است، با همهٔ همان قدمها، و بهاندازهٔ همان چیزی طول میکشد که این راهنما توصیف میکند. بدانید در هر لحظهٔ معین کدامیک را دارید، و توجه کنید که نوعِ دوم بسیار سادهتر است اگر پایگاهدادهٔ ماشینِ قدیمی را قادر به دریافتِ یک بازیابی نگه داشته باشید، نه اینکه جعبه را برای کارِ دیگری بازتخصیص دهید.
سرورِ قدیمی را برای حدودِ یک هفته نگه دارید: روشن، read-only، TTLِ DNS همچنان پایین، مانیتورینگ همچنان بهسمتش. روی کوچکترین پلن، آن بیمه چیزی حدودِ دو دلار هزینه دارد، که عددی نیست که باید در تصمیم نقش داشته باشد. چیزی که باید نقش داشته باشد این است که یک هفته بهاندازهٔ کافی طولانی است تا کارهای cron هفتگی، گزارشهای تقریباًماهانه، و یکپارچهسازیای که فقط جمعهها فعال میشود، دستِکم یکبار روی میزبانِ جدید اجرا شده باشند — اینها همان شکستهاییاند که یک پنجرهٔ دوروزه کاملاً از قلم میاندازد.
بعد عامدانه از رده خارجش کنید. تأیید کنید لاگِ دسترسیِ میزبانِ قدیمی برای یک روز تخت بوده. یک پشتیبانِ نهایی از آن بگیرید و بیشتر از آنچه فکر میکنید لازم است نگهش دارید. هر چیزی را که نگه داشته باطل کنید: کلیدهای API، کلیدهای deploy، کاربرانِ پایگاهداده، ورودیهایش در allowlistهای IP افرادِ دیگر، چکهای مانیتورینگش، ورودیِ SPF اش، رکوردِ MX اش. نمونه را نابود کنید. و در آخر TTLهای DNS را به چیزی معقول برگردانید — یک TTLِ دائمیِ 300 ثانیهای یعنی resolverها برای بقیهٔ عمرِ سایت بیست بار در ساعت دوباره اعتبارسنجی میکنند، که بعد از تمامشدنِ مهاجرت هیچ سودی برایتان ندارد و روی هر lookup سردی کمی تأخیر هزینه میکند. یک ساعت مقدارِ دائمیِ معقولی است؛ یک روز هم برای رکوردهایی که هرگز انتظار ندارید سریع تغییر کنند خوب است.
مهاجرت، به همان ترتیبی که باید اجرایش کنید
یک هفته مانده، ماشینِ قدیمی را فهرستبرداری کنید و runbook را بنویسید: بستهها، واحدهای فعالشده، crontabها، فایروال، ساکتهای در حالِ گوشدادن، نقشهای پایگاهداده، و هر شخصِثالثی که آدرسِ قدیمی را allowlist کرده. سه روز مانده، VPS جدید را تأمین کنید، رویش بازیابی کنید، و کلِ کار را با hostname و یک override برای resolver تمرین کنید — بعد یکبار فقط از روی فهرست بازسازیش کنید تا ثابت شود فهرست واقعی است. دو روز مانده، TTLهای A، AAAA و MX را به 300 پایین بیاورید تا پیش از اینکه نیازشان داشته باشید پایین باشند، یک TTLِ کاملِ قدیمی بگذرد.
یک روز مانده، اولین پاسِ rsync را با -aHAX --numeric-ids درحالیکه تولید ادامه دارد اجرا کنید، و replication پایگاهداده را راه بیندازید یا پنجرهٔ dump را روی dataset واقعی اندازه بگیرید. گواهیها را هم در همین پاس سروسامان دهید — دایرکتوریِ گواهی شاملِ کلیدِ حسابِ ACME را کپی کنید، یا به DNS-01 سوییچ کنید — و رکوردِ PTR و ورودیِ جدیدِ SPF را روی آدرسِ جدید تنظیم کنید، پیش از اینکه چیزی از آن ایمیل بفرستد.
در پنجره: نوشتنها را متوقف کنید، rsync نهایی را با --delete اجرا کنید، پایگاهداده را تمام کنید، سرویسها را شروع کنید، در برابرِ hostname واقعی روی مسیری که پایگاهداده را لمس میکند تأیید کنید، تأیید کنید درخواست در لاگِ میزبانِ جدید نشسته، و فقط بعد از آن DNS را تعویض کنید. میزبانِ قدیمی را روشن و read-only بگذارید. هر دو لاگِ دسترسی را تماشا کنید تا قدیمی تخت شود.
یک هفته بعد: تأیید کنید کارهای هفتگی روی میزبانِ جدید اجرا شدهاند، یک پشتیبانِ نهایی از قدیمی بگیرید، کلیدها و ورودیهای allowlist اش را همهجا باطل کنید، نابودش کنید، و TTLها را دوباره بالا ببرید. اگر میخواهید ماشینِ جدید بهتر از آنکه ترک کردید باشد، نه فقط تازهتر، پانزده دقیقهٔ اولِ سختسازی قدمِ بعدیِ طبیعی است، و انجامش روی سروری که هنوز لایهٔ مستندنشدهٔ خودش را انباشته نکرده خیلی سادهتر است. اگر هنوز دارید انتخاب میکنید کجا فرود بیایید، راهنمای حوزهٔ قضایی اینکه واقعاً بینِ ایسلند، هلند، رومانی و سوئیس چه فرقی هست را پوشش میدهد — و میتوانید ماشینِ مقصد را در حدودِ یک دقیقه روشن داشته باشید تا همین امروز تمرین را شروع کنید.