למה איזון GPU נשבר תחת עומס
תור משימות למספר יחידות חישוב נראה אחיד רק על הנייר. בזרימה אמיתית, בקשות קצרות למודל משולבות עם משימות אימון ארוכות, וחלקן מגיעות בקבוצות מאותו שירות. כל עוד איזון GPU מסתמך על מספר החיבורים, ולא על התפוסה בפועל של יחידת החישוב, ההתפלגות סוטה מהעומס האמיתי.
מכאן מתחילה מפולת: צומת שקיבל כמה משימות כבדות מחזיק בהן עשרות דקות, בקשות חדשות מצטברות בתור, וזמן התגובה גדל באופן לא ליניארי. יחידות החישוב השכנות בינתיים בטלות — עומס לא מאוזן הופך לזמן בטלה של יחידת החישוב, שאותו משלם הלקוח.
סכמות טיפוסיות כמו סבב היקפי או בחירת צומת עם המספר הקטן ביותר של בקשות פעילות נשברות מיד: הן לא רואות את אורך התור, הזיכרון השמור וזמן ההרצה של משימות קודמות. עומס יתר על צומת נוצר לא מגל תעבורה, אלא מכך שהמתזמן לא יודע כמה עבודה כבר התקבלה בכל יחידת חישוב.
מכאן גם התסמין המוכר: תפוסה ממוצעת של כלל הצי נשמרת ברמה תקינה, וזמן ההמתנה של משימות בודדות גדל פי כמה. בהמשך נפרט איך זה נסגר — באמצעות בקרת תור, משקלי צמתים וניתוב לפי תפוסה בפועל, ולא לפי מונה חיבורים.
אפקט של התפלגות עומס: תור, בטלה, כשלים
בהצמדה סטטית של משימות למאיצים מסוימים העומס מתפזר לא שווה: צומת אחד מחשב על הקצה, השני בטל. התור גדל בצומת העמוס ובטל בצומת הפנוי, וזנב ההמתנה נקבע לפי הבקשה הארוכה ביותר מלפנים — משימות קצרות עומדות אחרי ארוכות.
התפלגות מנוהלת מסירה זאת ברמת התכנון. המתזמן מסתכל על הזיכרון הפנוי של יחידת החישוב, סוג הפרופיל, עדיפות המשימה והיסטוריית הכשלים של הצומת; בידוד NVIDIA מאפשר לחתוך מאיץ אחד לפרופילים בלתי תלויים, כך שמודל גדול וזרם הסקות קטנות לא מתחרים על אותו משאב.
צומת שמחזיר שגיאות או איבד קשר עם מאגר המודלים מוצא מהרוטציה עד לבירור הסיבה, ולא אחרי קריסת משימות.
המדדים משתנים באופן צפוי. העומס על יחידות החישוב מתאזן: במקום פיזור של 40–90% נשמר 80–85% בכל הצי. זמן ההמתנה בתור מתקצר פי כמה בזכות כך שהחציון מפסיק להיות תלוי בזנב, ותפוקה גדלה פי 1.8–2 באותו מספר מאיצים.
גם סוג הכשלים משתנה: נעלמות שגיאות "המשימה לא הופעלה בגלל חוסר זיכרון" ופסקי זמן עקב עומס יתר על הצומת, ונשארים כשלים בודדים של יחידת חישוב מסוימת, שמכובים בחזרה על פרופיל שכן.
תחת עומס שיא המערכת מתדרדרת ברכות — זמן ההמתנה של משימות בעדיפות נמוכה גדל, אבל דחופות ממשיכות לעבור, במקום להפיל את כל הצומת יחד עם משימות זרות.
מצבי איזון GPU: השוואת גישות
מצב ההתפלגות קובע לאיזה צומת עם מאיץ תגיע כל בקשה, וממנו תלויים ניצולת הצי ופיזור זמן התגובה. בבחירה כושלת חלק מהצמתים בטלים, והתור מצטבר על אחד — זנב ההשהיות גדל מהר יותר מהעומס הממוצע.
אנחנו מתאימים מצב לפרופיל העומס: אורך ההקשר, שיעור הקריאות הקריטיות, זמן ההמתנה המותר למשימות רקע. להלן גישות שפוגשים בפועל והמגבלות שלהן.
| מצב | מתי מתאים | מגבלות |
|---|---|---|
| סבב היקפי | בקשות קצרות ואחידות, צמתים בעלי אותה עוצמה | לא מתחשב באורך המשימות בפועל: צומת אחד צובר קריאות איטיות, האחרים בטלים |
| לפי עומס נוכחי | זרימה מעורבת, אורך יצירה שונה | דרוש איסוף מדדים מתמיד מהצמתים; בסקירה נדירה ההחלטות מאחרות |
| תור משותף עם עדיפויות | קריאות קריטיות לצד משימות אצווה ברקע | בקשות בעדיפות נמוכה ממתינות יותר — נדרשת בקרה כדי שלא יגוועו ברעב |
| שמירת צמתים | שירות עם דרישת זמן תגובה נוקשה | חלק מוקצה מהקיבולת בטל בשעות עומס נמוך |
| הצמדת משימות לצמתים | מודלים גדולים עם טעינת משקלים ארוכה | הגמישות יורדת: אי אפשר להעביר את הצומת במהירות למודל אחר |
בפועל, לרוב עובד שילוב: תור בעדיפות לקריאות אינטראקטיביות פלוס רזרבה קטנה של צמתים עבורן, ומשימות אצווה כבדות עוברות למאגר המשותף. מערך כזה נותן זמן תגובה צפוי בלי קיבולת בטלה, אבל נבדק רק על פרופיל הבקשות האמיתי — לכן אנחנו מצלמים אותו לפני ההגדרה, ולא אחריה.
שלבי הגדרת התפלגות בקשות בין צמתים
סדר העבודות כמעט לא תלוי במודלים שמשרתים: תחילה מודדים את זרימת הבקשות האמיתית, אחר כך מתכננים את ההתפלגות, ורק אחר כך מפעילים אותה בתעבורה חיה. בלי תמונת הזרימות, כל איזון הופך לבחירת משקלים באקראי, והגל הראשון מראה שהתור גדל במקום לא צפוי.
- ביקורת זרימות משימות. מצלמים פרופיל פניות לאורך כמה ימים: אילו בקשות קצרות ותכופות, אילו כבדות ונדירות, היכן השיאים, כמה נמשכת ההמתנה בתור ואיזה חלק מהכשלים נובע מעומס יתר. בפלט — טבלה של סוגי משימות עם המשקל שלהן וזמן התגובה המותר.
- סכימת התפלגות. בוחרים מה להניח בבסיס ההחלטה: מספר בקשות פעילות בצומת, עומס הזיכרון בפועל של המאיץ או תור ההמתנה. למשימות קצרות משקלים מסוימים, לארוכות — אחרים: ערבוב שלהן באותו מאגר כמעט תמיד אומר שבקשה כבדה תופסת מקום בזמן שהקלות בטלות.
- הגדרת עדיפויות ותורים. מפרידים זרימות לפי מחלקות, קובעים זמן המתנה מקסימלי וכללי ניסיונות חוזרים, מתארים התנהגות כאשר צומת יוצא מכלל פעולה — הבקשה צריכה לעבור לצומת חי, ולא להמתין לכשל. כאן גם קובעים אילו משימות מאפשרות הפחתת דיוק החישוב לשם מהירות.
- בדיקה תחת עומס. מריצים את הפרופיל שנלקח בביקורת, עם מרווח של פי כמה ועם שיאים מלאכותיים: בודקים איך משתנה זמן התגובה באחוזון ה-95 של הבקשות, איך מתאזן העומס בין הצמתים ומה קורה כשמכבים אחד מהם.
- העברה לתפעול. מוסרים את סכימת ההתפלגות, הספים המוגדרים, לוחות בקרה עם מדדי המפתח והוראות להוספת צמתים חדשים — כדי שההרחבה לא תדרוש בנייה מחדש של הלוגיקה מאפס.
תארו את זרימת המשימות שלכם — נחזור עם תוכנית עבודה והערכה.
ערכת קונפיגורציות, סכמות ותקנות
העבודות מסתיימות לא בהדגמה, אלא במסירת ערכה שאיתה הצוות שלכם מתפעל את איזון המאיצים ומשנה אותו בלעדינו. הכול מעוצב כך שמהנדס חדש יבין מהמסמכים, ולא מהתכתבות.
- קונפיגורציית צמתים — ערכי פרמטרים של התפלגות בקשות, מגבלות זיכרון ועדיפויות תורים, עם סימון מה אפשר לשנות בחופשיות ומה קשור להגדרות שכנות.
- סכמות זרימות בקשות — המסלול מנקודת הכניסה ועד מאיץ מסוים, נקודות כשל והתנהגות המערכת כשצומת נופל מהרוטציה.
- תקנון תחזוקה — סדר עבודות מתוכננות: הוצאת צומת, חימום, החזרה לפעולה, עדכון פרופילים בלי לעצור את השירות.
- מדיניות גישה — תפקידים והרשאות: מי משנה פרמטרי איזון, מי רואה רק מדדים, איך כל שינוי מתועד.
- תיעוד המערכת — ארכיטקטורה, מילון מדדים, ניתוח כשלים טיפוסיים ורצף פעולות לכל אחד.
- מערך בדיקות — פאנל ניטור, ספי הפעלה ומסלולי התראות למשמרת תורנית.
- הליך חזרה לאחור — איך מחזירים פרופיל קונפיגורציה קודם בפעולה אחת ומה מאשר שהחזרה הצליחה.
הערכה חיה יחד עם המערכת: שינויים מוכנסים לאותם מסמכים וסכמות, ולא נאספים בהודעות נפרדות.
מקרה בוחן: איך צמצמנו את זמן הבטלה של יחידות החישוב פי שלושה
אלינו הגיע צוות שתפעל אשכול עם מאיצים מגוונים: חלק מהמכונות חישבו אימון, וחלק — הסקת מודלים בזמן אמת. המתזמן Kubernetes פיזר קונטיינרים לפי שארית, ובשני צמתים מתוך שמונה תמיד היה תור, בזמן שהשכנים בטלו. בקשות קצרות למודלים חיכו כמה דקות, והאימון פיספס לוחות זמנים.
הפרדנו את מאגר הצמתים לפי מחלקות משימות, הוצאנו את תפוסת המאיץ והזיכרון הגרפי למשאב תכנון נפרד והוספנו בדיקת חיות לפני הכנסה לתור — מעבד שקרס הפסיק להחזיק מקום. בנפרד כתבנו מחדש את העדיפויות: בקשה קצרה למודל כבר לא עומדת אחרי אימון של שעות.
מדדים לפני ואחרי: זמן הבטלה של יחידות החישוב הצטמצם פי שלושה, זמן ההמתנה בתור — משש דקות לארבעים שניות. פיזור העומס בין הצמתים הצטמצם מ-35–95% ל-70–85%, כלומר איזון העומס הפסיק להיות תלוי היכן המתזמן הציב את המשימה הראשונה. שיעור הבקשות שהושלמו עד תשובה בלי אתחול עלה ל-96%.
תוצאת ההטמעה — אותו צי מכונות מחזיק עכשיו פי שניים בקשות בו-זמנית, ואפשר להוסיף מאיצים בלי לכתוב מחדש את לוגיקת השירותים. כללי האיזון והעדיפויות נשארו בקונפיגורציה עם הערות, כדי שהצוות יתקן אותם בעצמו.
במה התפלגות בקשות שונה משמירת צמתים?
שמירת צמתים היא בעיקר קיום צומת חלופי לצד. צומת שני מוחזק פועל ומסונכרן עם הראשי, אבל זרימת המשימות בכל זאת הולכת לאחד — לפעיל. הרזרבה נכנסת לפעולה רק כשהראשי נופל, ועד אז היא לא מעבדת דבר.
מעבר בזמן תקלה סוגר חלק מהסיכון: השירות לא נופל כולו, ואחרי הפסקה ממשיך לעבוד. אבל לסכימה הזו יש גבול — בזמן המעבר בקשות ממתינות, חלק מהמשימות הארוכות נקטעות באמצע, והכפלת הצי לא נותנת תוספת תפוקה.
התפלגות בקשות פועלת ברמה גבוהה יותר. זרימת המשימות נחתכת למנות ומתפרסת על כל הצמתים החיים בהתחשב בתפוסה הנוכחית שלהם. כשל של צומת לא קוטע את הזרימה: בקשות שלא הגיעו אליו או לא הספיקו להסתיים עוברות לשכנים, ועמידות בכשלים הופכת לתוצאה של עומס אחיד, ולא של שכפול.
כדי שזה יעבוד, נדרש חשבון תפוסה של כל צומת, אורך התור וזמן התגובה, בדיקת חיות וניסיון חוזר תקין למשימות שנקטעו. נקודה מיוחדת — בקשות כבדות וארוכות: בלי מגבלה על המנה הן תופסות צומת שלם, והתור מצטבר גם כשהשכנים פנויים.
הגבול פשוט. שמירת צמתים עונה לשאלה "האם יש לאן לעבור", התפלגות — "האם הקיבולת לא בטלה והאם התור לא מצטבר". זמן בטלה של רזרבה תחת עומס לא אחיד לא נרפא בשכפול: עותק אחד נחנק, השני משועמם.
שאלות טכניות נפוצות על התפלגות עומס
המאזן עומד בין השירות למאגר המאיצים: מקבל בקשה, בוחר צומת לפי עומס זיכרון ואורך תור, ומחזיר תוצאה לקוד הקורא. לכן לפני הטמעה אנחנו מפרקים ארבע ספקות טיפוסיים של מהנדסים — תאימות לסכימה הנוכחית, מדדי בקרה, התנהגות בכשל צומת והיקף השינויים באפליקציה.
האם זה תואם לסכימה הנוכחית שלנו?
כן, אם האפליקציה פונה למודל דרך הרשת, ולא מחזיקה אותו בתוך התהליך שלה. אנחנו מתארים נקודות חיבור ושומרים על הכתובות הקודמות: השירות לא יודע שמספר הצמתים גדל — המסלול משתנה בצד המאזן.
באילו מדדים נשלטת ההתפלגות?
שיעור בקשות בכל צומת, עומק תור ההמתנה, זמן עד תשובה ראשונה ומספר ניסיונות חוזרים. פיזור עומס בין צמתים מעל 10-15% — סימן שהמשקלים או סף ההתחממות הוגדרו לא נכון.
מה קורה בכשל של צומת?
בדיקות חיות מוציאות צומת מהרוטציה תוך שניות, ובקשות שכבר נשלחו אליו חוזרות על צומת חי. הקוד הקורא מקבל תשובה, ולא שגיאה — אבל רק אם הקריאה החוזרת לא יוצרת כפילות, לכן אנחנו בודקים טיפול בניסיונות חוזרים בנפרד.
האם צריך לשנות את האפליקציה ואיך עוברת המיגרציה?
השינויים מינימליים: כתובת הפנייה ואישור ניסיונות חוזרים. מעבירים בהדרגה — תחילה שיעור מהבקשות, אחר כך כל הנפח, עם אפשרות להחזיר את המסלול הקודם בהגדרה אחת. אין צורך בהשבתה בזמן המעבר.
נדון במשימה שלכם: התפלגות עומס ועמידות בכשלים
כדי לחזור עם הערכה ותוכנית, ולא עם מילים כלליות, אנחנו צריכים תמונת מצב של הסכימה הנוכחית שלכם: איך בקשות מגיעות למאיצים, היכן נוצר התור — בכניסה למאזן, בתור המשימות, בגלל עומס שונה של האינסטנסים או בגלל כשלים של צמתים בודדים.
בהמשך נקבע יחד את הצבת המשימה והגבולות: מה נחשב להצלחה — עומס מטרה על המאיצים, זמן תגובה תחת שיא, התנהגות המערכת בנפילה של אינסטנס אחד.
- הצבת המשימה — מה בדיוק מאזנים ולפי איזה סימן: אורך הבקשה, סוג המודל, תפוסת זיכרון, עדיפות הלקוח.
- נתוני מקור — סכימת הפריסה הנוכחית, מצב הסקיילינג, לוגים ומדדים לתקופת הפעולה, תקלות ידועות והשלכותיהן.
- הערכה ותוכנית עבודה — אילו שינויים נוגעים רק למאזן, ואיפה יידרש לבנות מחדש את התור או לחלק מחדש את האינסטנסים.
- לוחות זמנים לשלבים — סדר: תחילה מצלמים מדדים, אחר כך מכניסים כללי התפלגות, ואחר כך בודקים התנהגות תחת עומס.
- פורמט שיתוף הפעולה — מי בצד שלכם נותן גישות לסביבה ולמדדים, איך מתאמים חלונות שינוי.
- קריטריוני קבלה — ספים מספריים לעומס ולזמן תגובה, שבהם אנו מחשיבים את העבודה כמושלמת.
תארו את המשימה בצורה חופשית וצרפו מה שיש במדדים — נחזור עם הערכה, תוכנית עבודה ולוחות זמנים לשלבים.







