چطور زمان بوت یونیتهای core را از چند ساعت به چند دقیقه رساندیم 🚀
Core شرکت ما یعنی دیتاسنترهای متمرکز که وظیفهٔ کنترلپلن (control plane)، صورتحساب (billing) و تحلیلها (analytics) را بر عهده دارند — جدا از edge توزیعشدهای که ترافیک کاربران را هندل میکند. سرورهای core ما bare metal هستند و وقتی در فرآیند ریبوت مشکلی پیش بیاید، اثرات آن میتواند خیلی سریع پخش شود. این بوت از طریق UEFI (فِرمویر مدرن) هماهنگ میشود که سختافزار را مقداردهی اولیه میکند و کنترل را به OS میسپارد؛ نکات ریز در همین handoff میتوانند پیامدهای بزرگی داشته باشند.
بعد از یک آپدیت فِرمویر معمولی، بعضی از سرورهای core ما بهجای چند دقیقه، چهار ساعت طول میکشیدند تا آنلاین شوند. ⏳ آنچه باید یک rollout یکروزه میبود، به چند روز کشیده شد. نودهای جدید در اولین بوتشان با تمام timeoutها روبهرو میشدند، Maintenance windowها بزرگتر شدند و تیمها مجبور شدند آپگریدهایی را که باید بدون نظارت اجرا میشدند، دستی مراقبت کنند.
این مشکل تمام ناوگان Gen12 — نزدیک به 2,000 واحد — را تحت تأثیر قرار داد. هر failure غیرمنتظره در میانهٔ آپگرید یعنی شروع دوبارهٔ کل سیکل و ظرفیت جدیدی که به دلیل زمانهای انتظار طولانی عملاً بیکار میماند ⚠️.
این گزارش داستان دنبالگیری علت تا رسیدن به یک quirک در فِرمویر و یک جستجوی خطی بیش از حد eager روی هر network boot interface ممکن است — و چطور کل زمان بوت و آپگرید را از ساعتها به چند دقیقه برگرداندیم. در مسیر، چیزهایی دربارهٔ UEFI internals، quirks مختص vendorها و استراتژیهای اتوماسیون که مشکل را حل کردند، به اشتراک میگذاریم 🔍.
The network boot interface: یک network boot interface به سرور اجازه میدهد OS را از طریق شبکه بهجای storage محلی بوت کند. این برای کنترل متمرکز، اتوماسیون و مقیاسپذیری بوتها حیاتی است، بهویژه وقتی ناوگان جهانی و با workloads مختلف داریم. دو رابط اصلی PXE و UEFI HTTPS boot هستند.
در فرایند ریبوت ما معمولاً برای دلایل اتوماسیون از PXE عبور میکنیم. ما از open-source iPXE استفاده میکنیم؛ یک network boot firmware که از پروتکلهای مدرن مثل HTTP/HTTPS پشتیبانی میکند. iPXE اجازه میدهد سیستمها OS را مستقیم از وبسرورها، cloud یا storage enterprise بوت کنند — با سرعت و پایداری بهتر.
iPXE فرایند بوت را به یک workflow قابل برنامهریزی تبدیل میکند و scriptingهای پیشرفتهای دارد که اتوماسیون پروویژنینگ پیچیده و مدیریت workstationهای diskless امن را ممکن میسازد. بعضی سختافزارهای ما از HTTPS-based UEFI network boot هم پشتیبانی میکنند که اجازه میدهد firmware مادربرد بهصورت Native فایلهای OS را بهصورت امن دانلود کند.
The linear search: قصهٔ ما از همان آپدیت فِرمویر شروع شد. بعد از آپدیت اولین گزارشها نشان دادند سرورها آنلاین نمیشوند؛ داشبوردها ماشینهایی را نشان میدادند که در حالت pre-OS مدت بسیار بیشتری از انتظار باقی ماندهاند. ابتدا فکر کردیم regression در فِرمویر رخ داده. برای رد این احتمال، کنسول سریال یک ماشین معیوب را باز کردیم و بوت را لحظهبهلحظه دیدیم. POST و مقداردهی سختافزار طبیعی بهنظر میرسید، اما بعد از آن بهجای رفتن سریع به مرحلهٔ network boot و دریافت ایمیج OS، سیستم ایستاد. و ایستاد.
خروجی کنسول نشان داد سیستم دارد ابتدا تلاش میکند IPv4 HTTPS network boot انجام دهد، بعد چند دقیقه timeout میشود، سپس IPv4 iPXE را امتحان میکند، دوباره timeout، و این دو را تکرار میکند — تا نهایتاً IPv6 HTTPS که موفق میشود برسد. هر تلاش ناموفق تقریباً پنج دقیقه timeout میسوزاند؛ با چهار تلاش روی هم، یک بوت حدود بیست دقیقه تلف میشد. برای یک ریبوت ساده دردناک است؛ اما برای اتوماسیون آپدیت فِرمویر که نیاز به چندین ریبوت متوالی دارد، این 20 دقیقهها جمع شده و برای هر سرور نزدیک چهار ساعت انتظار ایجاد میکردند ⏱️.
راه حل: دیگر جستجو نکن — boot interface را اعلام کن. بعد از پی بردن به الگوی timeout، علت مشخص شد: سرورها بدون دانستن درست، یکییکی همهٔ network boot interfaceها را امتحان میکردند و منتظر timeout میشدند. راه حل ساده اما مؤثر این بود که بهجای حدس زدن، interface درست را از ابتدا declare کنیم تا زمان روی interfaceهای نامناسب هدر نرود. اما پیادهسازی این راه حل موانعی داشت: ترتیب workflow اتوماسیون بوت، تنظیماتی که توسط vendor قفل شده بود، و فرمتهای متفاوت رشتهها از NICهای مختلف. ✅
Workflow اتوماسیون بوت ما سه مرحلهٔ کلی دارد: firmware initialization، pre-boot و kernel startup. بعد از Power On، فِرمویر UEFI مقداردهی سختافزار و پِریفرالها را انجام میدهد و سپس PXE pre-boot اجرا میشود. در مرحلهٔ pre-boot کارت شبکه پیکربندی و یک برنامه کوچک بهنام bootloader اجرا میشود که کرنل را kickstart میکند. همین جاست که چند interface شبکه برای پیدا کردن گزینهٔ درست پروب میشوند. از آنجا که هر آپدیت فِرمویر یک ریبوت نیاز دارد، همین باعث شد زمانها انباشته شوند و به ساعتها برسند.
با بازآرایی توالی اتوماسیون و اعلام ترتیب network boot interfaceها زودتر در مرحلهٔ pre-boot PXE برای هر سختافزار/use-case، توانستیم کل زمان را حدود یک ساعت کاهش دهیم چون دیگر لازم نبود برای هر آپدیت 20 دقیقه صرف پروب شود. برای موارد لبهای، دو محدودیت خاص پیش آمد: پشتیبانی Legacy: ترتیب بوت روی نسخههای قدیمی UEFI پشتیبانی نمیشود، و Persistence: بعضی تنظیمات پس از آپدیت فِرمویر ریست میشوند. برای اینها یک مرحلهٔ state validation اضافه کردیم: اتوماسیون فِرمویر پس از هر تغییر config را چک میکند؛ اگر متوجه بازنشانی شد، config را مجدداً اعمال و reboot را تریگر میکند. اگرچه بوت اول ممکن است کمی طولانیتر شود، اما این تغییر زمان بوتهای بعدی را از حدود 20 دقیقه به کمتر از یک دقیقه کاهش میدهد 🔧.
تنظیم ترتیب بوت که vendor آن را غیرفعال کرده بود: ساختار داخلی تنظیمات Network Boot یک EFI_IFR_REF3 است که lazy loaded بود — یعنی دادهها تا زمانی که از طریق callback GUI فراخوانی نشوند بارگذاری نمیشوند. این باعث شد “Network Boot Interface” برای اسکنهای برنامهریزیشدهٔ ما نامرئی بماند چون ساختار هنوز load نشده بود. برای توضیح بهتر، ساختار در متن اولیه به این شکل بود:
typedef struct _EFI_IFR_REF3 {
EFI_IFR_OP_HEADER Header;
EFI_IFR_QUESTION_HEADER Question;
EFI_QUESTION_ID QuestionId;
EFI_GUID FormSetId;
} EFI_IFR_REF3;
این رفتار که برای شتاببخشیدن به زمان بوت BIOS مرسوم است، باعث شد اتوماسیون ما نتواند اولویتها را کشف کند. با vendorها همکاری کردیم تا tokenهای مشخصی را در “Boot Order Module” فعال کنند تا discoveryِ Network Boot Interface در طول بوت انجام شود بدون نیاز به تعامل دستی با GUI. بعضی UEFIهای سازندهٔ تجهیزات یک تنظیم غیرقابلتغییر داشتند (Force Priority Httpv4 Httpv6 Pxev4 Pxev6) که مانع تغییر ترتیب بوت میشد؛ رفع این مورد نیاز به BIOS جدید از سمت vendor و یک جلسهٔ دیباگ داشت.
رشتههای متفاوت از NICهای مختلف: بسته به vendor کارت شبکه، رشتههای نمایش متفاوت بودند و وقتی میخواستیم ترتیب بوت را از طریق iPXE تنظیم کنیم، mismatch ایجاد میشد. مثالها:
UEFI: HTTPS IPv4 Ethernet Network Adapter XXX-XXX-Y for OCP 3.0 P1
UEFI: HTTPS IPv4 Network Adapter – 50:00:E6:8F:4F:32 P1
برای حل این مشکل، به ابزار CfHIIConfig_App یک قابلیت اضافه کردیم تا بتواند config را بدون داشتن رشتهٔ کامل تنظیم کند، با استفاده از الگوهایی مانند:
.*HTTP.*IPv4.*P1
این الگوها با رشتههای پذیرفتهشده مطابقت داده میشدند و ترتیب بوت صحیح انتخاب میشد. در حال همکاری با vendorهای UEFI هستیم تا رشتهٔ network interfaceها استاندارد شوند و تنها اطلاعات مرتبط (مثل protocol، transfer type، port number و physical slot index) استفاده شوند و جزئیات محصول مثل MAC address حذف شوند. اطلاعات محصول در صورت نیاز از VPD (vital product detail) خوانده خواهد شد. این کار drift در تنظیمات و نیاز به wildcards را حذف میکند 🧩.
عدم توانایی برای چک کردن config از طریق iPXE: iPXE این متغیرها را بهصورت HEX میخواند، پس خروجی رشته را بهصورت hex میدید. برای تشخیص اینکه آیا تنظیمات شبکه تغییر کرده و برای کاهش زمان بوت (تا مجبور نباشیم قبل از ست کردن متغیرها آنها را پرینت کنیم)، یک flag بولی بهنام uefi-same-hex اضافه کردیم که نشان میدهد آیا config تغییر کرده یا نه. با این کار بهجای ابتدا اجرای show برای مقایسه و سپس set در صورت نیاز، میتوانستیم تنها یک دستور set اجرا کنیم و سادهتر عمل کنیم. نمونهٔ دستورات مسیرخواندن و تنظیم که استفاده میشوند بهصورت زیر هستند:
# construct path to read the update variable
set buffer-var-guid 91468514-75bc-4bb5-8f33-91efff9e9b1f
set var-upd-path efivar/CfHIIVarUpd-${buffer-var-guid}
# Run the config change command
نتیجه: با این ترکیب از تغییر ترتیب بوت در مرحلهٔ pre-boot، همکاری با vendorها برای باز کردن tokenهای لازم، سازگارسازی رشتهها و بهبود منطق iPXE، توانستیم زمان بوت و آپگرید را از ساعتها به دقیقهها برگردانیم. این تغییر نه تنها زمان را کم کرد، بلکه نیاز به مداخلهٔ دستی را هم بهطور چشمگیری کاهش داد. درسهای کلیدی: فهم عمیق UEFI internals، هماهنگی نزدیک با سازندگان سختافزار، و پیادهسازی اعتبارسنجی وضعیت پس از تغییرات، پایهٔ اتوماسیون قابلاعتماد برای ناوگانهای بزرگ است ⚙️.