گوگل چطور Borg را به دنیا آورد؟!

سال ۲۰۲۰ کتابی با عنوان مهندسی نرم افزار در گوگل(Software Engineering at Google) توسط جمعی از اعضای اسبق(که به عنوان Xoogler شناخته می‌شوند) و نویسندگان فنی منتشر شد که تجربیات مهندسی در گوگل و چالش‌هایی که طی زمان با آن مواجه شده اند را با مخاطب به اشتراک می‌گذاشت.

به لطف کیانوش مختاریان که از مهندسین نرم افزار گوگل است فرصت داشتم فصل آخر کتاب را که مرتبط با حوزه کاری‌ام بود بخوانم.

این فصل به مفهوم «پردازش به عنوان خدمت»(Compute as a Service) پرداخته و به قول نویسنده داستان رسیدن از مسئله ساده‌‌:

«فقط بهم سخت افزار بده تا کارم رو انجام بدم»

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

نوعی تاریخچه چالش محور، به این معنا که تک تک مشکلاتی را که تیم مهندسی با آن روبرو شده و برای حل آن راهکار ارائه داده با مثال توضیح داده است، پیدایش سیستم معروف Borg است.

جالب است بدانید که این سیستم را می‌توان جد بزرگ راهکارهای ابری گوگل همچون Cloud Platform، AppEngine،Kubernetes و ... دانست.

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

این اولین مطلب شامل معرفی هر بخش و همچنین مرور اولی است:

  1. رام کردن محیط پردازش
    رام کردن(Tame) را نویسنده به عمد انتخاب کرده تا دشوار بودن تسلط بر محیط پردازشی را، که مثل رام کردن یک گاو وحشی با دشواری همراه است ، نشان دهد پس من هم از معادل مرتبط آن استفاده کردم.
    این بخش به چگونگی رسیدن گوگل به راه حل‌هایش برای مشکلات این حوزه و بعضی مفاهیم کلیدی CaaS می‌پردازد.
  2. نوشتن نرم‌افزار برای پردازش مدیریت شده
    نشان می‌دهد چطور یک راهکار پردازش مدیریت شده روی نحوه نوشتن نرم‌افزار توسط مهندسین تاثیر گذاشت. به طوری که نویسنده معتقد است مدل انعطاف پذیر برنامه ریزی(Scheduling) موسوم به «احشام، نه حیوانات خانگی»(Cattle, not pets) اساس موفقیت گوگل در ۱۵ سال اخیر بوده و ابزاری مهم در جعبه افزار هر مهندس نرم‌افزار کنونی است.
  3. پردازش به عنوان خدمت(CaaS) در گذشت زمان و حین مقیاس‌دهی
    روی درس‌هایی که گوگل درباره نقش انتخاب‌های اش در معماری راهکارهای پردازشی حین تکامل و توسعه سازمان گرفته، تمرکز کرده است.
  4. و در آخر، انتخاب خدمات پردازشی
    به مهندسینی که انتخاب یک راهکار پردازشی به دوششان گذاشته شده، اختصاص یافته و عواملی که به آن‌ها کمک می‌کند را بررسی کرده.

رام کردن محیط پردازش

همانطور که گفتیم Borg، که یکی از ابزار داخلی گوگل است، جد بسیاری از راهکارهای امروزی CaaS همچون Kubernetes و Mesos است.

دنبال کردن فرایند رشد و تکامل آن و زحمات مهندسین گوگل برای رام کردن محیط پردازشی مد نظرشان می‌تواند به درک نحوه توسعه و تکامل متقابل این سازمان کمک کند.

خودکارسازی کارهای پر زحمت

اگر در شروع قرن حاضر قصد استقرار(Deploy) نرم‌افزارتان روی سروری را داشتید احتمالا کار با انتقال کد از طریق SFTP و پیگری کار با SSH ختم می‌شد.

با افزایش تعداد ماشین‌ها، که در عصر حاضر امری اجتناب ناپذیر است، کار سخت و انجام دستی آن زمان‌بر و مستعد خطا(Error-Prone) بود.

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

برای مثال نویسنده نقل قولی از Jeff Dean یکی از مهندسین ارشد گوگل درباره راه انداختن یکی از فرایندهای خودکار پردازش داده به عنوان بخشی از رویه انتشار نرم‌افزار آورده که به مضمون می‌شود:

راه اندازی این تسک کابوسی لجستیک و زمان‌بر است.
در حال حاضر نیاز دارد فهرست اسامی بیش از ۵۰ سرور را دریافت، رویه‌ای را روی آن اجرا و بعد پیش‌رفت کار را نظارت کند.
هیچ پشتیبانی‌ای از مهاجرت خودکار پردازش جاری به ماشین دیگر در صورت به خطا خوردن یکی از ماشین‌ها نیست و نظارت بر پیشرفت کارها به شکلی سنتی و بدون انعطاف انجام می‌شود.
فراتر از این قضایا از آنجایی که رویه‌ها ممکن است تداخل داشته باشند یک فایل ثبت نام دست نوشت و پیچیده برای کنترل استفاده از ماشین‌ها وجود دارد که کار برنامه ریزی را غیر بهینه می‌کند و جدال بر سر منابع کمیاب را افزایش می‌دهد.

این یکی از اولین عوامل شروع کننده تلاش‌های گوگل برای مهار محیط پردازشی بود و توضیح می‌دهد که چطور راهکارهای بسیط(Naive) در مقیاس وسیع غیر قابل نگهداری می‌شوند.

خودکارسازی‌های ساده

سازمان‌ها می‌توانند اقدامات ساده‌ای برای کاهش این زحمات انجام دهند.

مثلا می‌توانند با نوشتن یک Shell Script، یا اگر قابل استفاده مجدد بود به شکل کدهای یک زبان برنامه نویسی، فرایند استقرار را به طور موازی روی سرورها اجرا کنند.

یا حتی جالبتر اینکه فرایند نظارت(Monitoring) هم می‌تواند خودکار باشد.

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

این یعنی باید بتوان سنجه‌هایی(Metrics) را از رویه استخراج کرد و آن را در یک فضای اشتراکی ذخیره کرد یا به سیستم مانیتورینگی فرستاد که در آن‌جا اختلال‌ها در یک نگاه قابل تشخیص باشند(مثلا با ذخیره کردن سنجه‌هایی مثل «زنده بودن رویه»(process is alive) یا «تعداد سندهای پردازش شده»).

به عنوان راهکارهای متن‌باز فعلی در این حوزه هم می‌توان از پرومتئوس و گرافانا استفاده کرد.

حال اگر اختلالی مشاهده شد چه؟

استراتژی سنتی مقابله با این مسئله ارتباط SSH به سرور و راه اندازی مجدد رویه است که پیشتر گفتم فرایندی زمان‌بر و پر خطا است و می‌توان آن را به این شکل خودکار کرد:

  • به جای نظارت شخصی از عاملی(Agent) روی ماشین استفاده می‌کنیم که وظیفه کشف اختلال و بعد راه اندازی مجدد رویه را دارد.
  • به جای ورود به ماشین و دستی اجرا کردن فرامین تکراری می‌شود آن‌ها را در قالب شل اسکریپتی ذخیره کرد و با استفاده از یک حلقه ساده برای کشف خطا، اسکریپت را اجرا کرد.

معادل این کارها در عالم رایانش ابری(Cloud) همان تنظیم سیاست‌های التیام خودکار(Self-healing Policies) است( مثلا برای کشتن و راه اندازی مجدد یک ماشین مجازی(VM) یا دربرگیرنده(Container) ).

این اقدامات شاید بخشی از مشکلاتی که Dean گفته بود را حل کند ولی مسائل پیچیده تری هم وجود دارد.

برنامه ریزی خودکار

طبیعتا قدم بعدی، واگذاری برنامه ریزی استقرار از عامل انسانی به کامپیوتر است که احتمالا اولین خدمت(Service) واقعی در حوزه CaaS محسوب می‌شود و سنگ بنای Borg را تشکیل می‌دهد.

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

برای بسط دادن این قابلیت می‌توان اسکن لاگ‌های ماشین‌ها جهت کشف خطا و مشکلات را هم به سیستم اضافه کرد تا در صورت وقوع خطا به مهندسین هشدار داده شود و از برنامه‌ریزی جهت استقرار رویه‌ها روی ماشین مذکور جلوگیری کنیم.

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

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

دربرگیرندگی و چند مستاجری

اگر قرارباشد جهت بهینگی استفاده از سخت افزار، چند برنامه روی یک ماشین مستقر شود چه؟

در این صورت به مشکلاتی برمی‌خوریم مثلا توسعه طبیعی برنامه یا نشت حافظه آن ممکن است باعث اختلال در کارکرد دیگران شود یا امور خاصی مثل دسترسی اختصاصی به دایرکتوری tmp/ ممکن نیست.

همچنین نسخه‌های مشخصی از کتابخانه‌ها و برنامه‌های پیش نیاز برای هر برنامه مورد نیاز است که با نسخه‌های دیگر تداخل دارد.

در مورد امنیت چه؟

قطعا باید راهی برای جلوگیری از نشت اطلاعات حساس هر برنامه وجود داشته باشد.

پس درجاتی از محصورسازی(Isolation) نیاز است تا پیشروی رویه اجرایی بدون مداخله دیگر طبقات(Tenants) را تضمین کند.

پاسخ کلاسیک به این مسئله مجازی سازی بود که باز هم محدودیت‌هایی داشت مثلا باید یک سیستم عامل کامل را درون هر نمونه(instance) از ماشین مجازی راه اندازی می‌کرد و بنابراین علاوه بر استفاده زیاد از منابع سخت افزاری سرعت بالا آمدن آن هم کند بود.

این راهکار خوبی برای پاسخگویی به کارهای دسته‌ای کوتاه مدت(short lived batch jobs) که باید به سرعت راه اندازی و اجرا می‌شدند نبود پس مهندسین طراح Borg در سال ۲۰۱۳ را مجبور کرد دنبال راه حل دیگری بگردند و در نهایت به استفاده گسترده از دربرگیرنده‌ها (Containers) منتهی شد.

این فناوری از قابلیت‌های مبتنی بر cgroups(که آن را هم مهندسین گوگل در ۲۰۰۷ به هسته لینوکس اضافه کردند)، chroot jails و امکانات محصورسازی فایل سیستم همچون Bind Mounts و Union/Overlay استفاده می‌کرد.

با گذشت زمان و تکامل بیشتر سازمان مشکلات بالقوه بیشتری در حوزه محصورسازی کشف شد مثل مشکلی که که در سال ۲۰۱۱ و حین کار روی Borg با فضای شناسه رویه‌ها(process ID space) پیش آمد.

سقف پیشفرض شناسه‌ها 32,000 بود و به نظر می‌رسید رو به اتمام است که باعث محدود شدن تعداد رویه‌ها و نخ‌های(Threads) هر Replica می‌شد و بعدا به آن دقیق‌تر می‌پردازیم.

اندازه‌دهی درست و مقیاس‌دهی خودکار

نسخه ۲۰۱۶ Borg کارها را بر اساس برنامه ارائه شده توسط مهندسین برنامه ریزی می‌کرد(مثل تعداد Replica و منابع مورد نیاز).

این به خودی خود مسئله ساز بود چرا که مهندسین باید اندازه این منابع را محاسبه می‌کردند و این باعث می‌شد که با گذشت زمان و توسعه سیستم زحمات و خطاهای اندازه گیری زیاد شود.

با خودکارسازی این بخش از کار نیز دیگر جایی برای نگرانی نبود.


خلاصه

توسعه یک سازمان و کامل‌تر شدن محصولات آن با رشد این موارد همراه است:

  1. تعداد برنامه‌های مختلفی که باید آن‌ها را مدیریت کرد.
  2. تعداد کپی‌های یک برنامه که نیاز به اجرا شدن دارند.
  3. اندازه بزرگترین برنامه

برای مدیریت موثر این افزایش مقیاس به خودکارسازی نیاز داریم.

باید انتظار توسعه خود فرایند خودکارسازی را هم داشته باشید(مثل برنامه‌ریزی برای GPU و TPU که یکی از بزرگترین تغییرات Borg در ۱۰ سال اخیر بود).

یکی از بزرگترین چالش‌های خودکارسازی در گوگل که هنوز هم در حال بهبود است فرایند خودکارسازی مدیریت مراکز داده(Data Centers) است.

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