גרסאות מבוזרות

כשיש לכם בסיס קוד גדול, שרשרת של יחסי תלות יכולה להיות עמוקה מאוד. לעיתים קרובות, קבצים בינאריים פשוטים יכולים להיות תלויים בעשרות אלפי יעדי build. בקנה מידה כזה, פשוט לא ניתן להשלים גרסת build בפרק זמן סביר: אף מערכת build לא יכולה לעקוף את חוקי הפיזיקה הבסיסיים שהוטלו על החומרה של המחשב. הדרך היחידה לבצע את העבודה הזו היא באמצעות מערכת build שתומכת בבניית גרסאות מבוזרות, שבהן יחידות העבודה שמתבצעת על ידי המערכת מתפרסות על מספר מחשבים שרירותיים וניתן להתאמה. בהנחה שאנחנו מפצלים את העבודה של המערכת ליחידות קטנות מספיק (פרטים נוספים בהמשך), זה יאפשר לנו להשלים כל מבנה בכל גודל שהוא במהירות שאנחנו מוכנים לשלם. יכולת ההתאמה היא הרוטש הקדוש שהתחלנו לעבוד עליו על ידי הגדרת מערכת בנייה המבוססת על פריטי מידע שנוצרו בתהליך פיתוח (Artifact).

שמירה במטמון מרחוק

הסוג הפשוט ביותר של גרסאות build מבוזרות הוא שיטה שמשתמשת רק בשמירה במטמון , שמוצגת באיור 1.

גרסת build מבוזרת עם שמירה במטמון במטמון

איור 1. מבנה מבוזר שמציג שמירה במטמון מרחוק

כל מערכת המבצעת גרסאות build, כולל תחנות עבודה של מפתחים ומערכות אינטגרציה רציפה, משתפת קובץ עזר של שירות מטמון מרוחק. השירות הזה עשוי להיות מערכת אחסון מקומית לטווח קצר, כמו Redis או שירות בענן, כמו Google Cloud Storage. בכל פעם שמשתמש צריך ליצור פריט מידע שנוצר בתהליך פיתוח (Artifact), אם באופן ישיר או אם הוא תלוי, המערכת בודקת תחילה עם המטמון המרוחק אם יש כבר פריט מידע כזה. אם כן, היא יכולה להוריד את פריט המידע שנוצר בתהליך פיתוח (Artifact) במקום לבנות אותו. אם לא, המערכת בונה את פריט המידע שנוצר בתהליך הפיתוח (Artifact) ומעלים את התוצאה חזרה למטמון. משמעות הדבר היא שניתן לבנות פעם אחת את קשרים בגובה נמוך, שלא משתנים לעיתים קרובות, ולשתף אותם בין משתמשים שונים במקום לבנות מחדש כל משתמש בנפרד. ב-Google, פריטים רבים מוצגים ממטמון ולא נבנים מאפס, וכך מפחיתים משמעותית את עלות ההפעלה של מערכת ה-build שלנו.

כדי שמערכת אבטחה מרוחקת תעבוד, מערכת ה-build חייבת להבטיח שניתן לשחזר אותה לחלוטין. כלומר, לגבי כל יעד build, צריכה להיות אפשרות לקבוע את הקבוצה של ערכי הקלט עבור היעד הזה, כך שאותה קבוצת קלט תיצור את אותו פלט בדיוק בכל מחשב. זו הדרך היחידה לוודא שהתוצאות של הורדת פריט מידע שנוצר בתהליך פיתוח (Artifact) הן זהות לתוצאות היצירה שלו. חשוב לשים לב שכל תוכנה

כמובן שכדי להפיק תועלת ממטמון מרוחק, הורדה של פריט מידע שנוצר בתהליך פיתוח (Artifact) צריכה להיות מהירה יותר מבנייתו. זה לא תמיד המקרה, במיוחד אם שרת המטמון נמצא רחוק מהמכשיר שבו הוא פועל. המערכת של Google ומערכת ה-build נבנו בקפידה כדי לאפשר שיתוף מהיר של תוצאות ה-build.

ביצוע מרחוק

שמירה מרחוק במטמון אינה מבנה מבוזר. אם המטמון אבד או אם אתם מבצעים שינוי ברמה נמוכה שדורש בנייה מחדש, עדיין תצטרכו לבצע את כל ה-build באופן מקומי במחשב. היעד האמיתי הוא לתמוך בתפעול מרחוק, שבו אפשר לבצע את העבודה בפועל על יצירת גרסאות שונות של עובדים. איור 2 מתאר מערכת הפעלה מרחוק.

מערכת ביצוע מרחוק

איור 2. מערכת ביצוע מרחוק

הכלי Build שפועל במחשב של כל משתמש (שבה משתמשים הם מהנדסי תוכנה או מערכות build אוטומטיות) שולח בקשות ל-build מרכזי. אלוף ה-build מסתמך על הבקשות שלהם כדי לבצע את הפעולות האלה ומתזמן את ביצוע הפעולות האלה למאגר עובדים שניתן לשנות את הגודל שלו. כל עובד מבצע את הפעולות שהתבקשו בהתבסס על הערכים שהוזנו על ידי המשתמש, וכותב את הקבצים הקשורים. פריטי המידע האלה משותפים בין כל הפעולות האחרות שמבצעות מכונות שמחייבות אותם עד שניתן להפיק את הפלט הסופי ולשלוח אותו למשתמש.

החלק הקשה ביותר בהטמעה של מערכת כזו הוא ניהול התקשורת בין העובדים, האמן והמכונה המקומית של המשתמש. ייתכן שהעובדים יתבססו על תוצרי ביניים שנוצרו על ידי עובדים אחרים, והפלט הסופי צריך להישלח בחזרה למכונה המקומית של המשתמש. לשם כך, אנחנו יכולים לבסס את המטמון המבוזר שתיארנו קודם על ידי כל אחד מהעובדים שלנו לכתוב את התוצאות שלו ולקרוא את תלויותיו מהמטמון. המאסטר מונע ממשתמשים להמשיך בתהליך עד שכל מה שהם תלויים בו מסתיים, כך שהם יוכלו לקרוא את הנתונים שנשמרו במטמון. המוצר הסופי גם נשמר במטמון, וכך מאפשר למכונה המקומית להוריד אותו. שימו לב שאנחנו גם צריכים אמצעים נפרדים לייצוא השינויים המקומיים בעץ המקור של המשתמש, כדי שהעובדים יוכלו להחיל את השינויים האלה לפני הבנייה.

כדי שזה יעבוד, כל החלקים של מערכות הבנייה המבוססות על חפצים שתוארו קודם לכן צריכים לפעול יחד. סביבות בנייה צריכות להיות מתוארות בעצמן לחלוטין כדי שנוכל לקלוט עובדים ללא התערבות אנושית. כל תהליך בנייה צריך להתבצע באופן עצמאי, כי ייתכן שכל שלב יבוצע במחשב אחר. התפוקה חייבת להיות דטרמיניסטית לחלוטין, כדי שכל עובד יוכל לסמוך על התוצאות שהוא מקבל מעובדים אחרים. למערכת כזו קשה מאוד לספק דרישות כאלה, וכתוצאה מכך קשה מאוד ליצור מערכת מהימנה להפעלה מרחוק.

גרסאות build מבוזרות ב-Google

משנת 2008, Google משתמשת במערכת build מבוזרת שמשתמשת גם במטמון מרוחק וגם בהפעלה מרחוק, כפי שמתואר באיור 3.

מערכת build ברמה גבוהה

איור 3. מערכת הבנייה המבוזרת של Google

המטמון המרוחק של Google נקרא ObjFS. היא מורכבת משרת עורפי לאחסון תפוקות ב-Bigtables, בכל צי המכונות שלנו ו-DUSE של FUSE של FUSE בשם objfsd, שפועל במכונה של כל מפתח. ה-Faemon של FUSE מאפשר למהנדסים לעיין בפלטי build כאילו הם קבצים רגילים המאוחסנים בתחנת העבודה, אבל כשמורידים תוכן מהתוכן לפי דרישה רק עבור הקבצים הקטנים שהמשתמש מבקש ישירות. הצגת תוכן קבצים על פי דרישה מפחיתה משמעותית גם את השימוש ברשת וגם את האחסון, והמערכת יכולה לבנות מהר פי שניים בהשוואה לשיטה שבה שמרנו את כל פלט הדיסק בדיסק המקומי של המפתח.

מערכת ההפעלה מרחוק של Google נקראת Forge. לקוח ב-Bulaze התזמון שומר מטמון של תוצאות הפעולה, ומאפשר לה להחזיר תשובה מיד אם הפעולה כבר נוצרה על ידי משתמש אחר במערכת. אם לא, הפעולה תבוצע בתור בתור. מאגר גדול של משרות מסוג 'מוציא לפועל' קורא באופן קבוע פעולות מ'הבאים בתור', מבצע אותן ושומר את התוצאות ישירות ב-ObjFS Bigtables. התוצאות האלה זמינות למנהלים לצורך פעולות עתידיות, או שמשתמשי הקצה מורידים אותן דרך objfsd.

התוצאה הסופית היא מערכת שניתנת להתאמה כדי לתמוך ביעילות בכל גרסאות ה-build שבוצעו ב-Google. קנה המידה של גרסאות ה-build של Google הוא עצום מאוד: Google מפעילה מיליוני גרסאות build שמבצעות מיליוני מקרים של בדיקות, ויוצרת פטה-בייט של פלטי build ממיליארדי שורות של קוד מקור מדי יום. לא רק שמערכת כזאת מאפשרת למהנדסים שלנו לבנות בסיסים מורכבים של קוד במהירות, היא גם מאפשרת לנו ליישם מספר עצום של כלים ומערכות אוטומטיים שמסתמכים על הבנייה שלנו.