פתרון בעיות של חלוקת תנועה לא אחידה

במאמר הזה מוסבר איך לפתור בעיות שקשורות לחלוקת תעבורה לא אחידה לשירותי Kubernetes.

זיהוי תסמינים של חלוקת תנועה לא אחידה

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

התסמינים הנפוצים כוללים:

  • צווארי בקבוק בביצועים: יכול להיות שהמשתמשים יחוו זמנים קצובים לתפוגה לסירוגין, שגיאות HTTP 5xx או אובדן מנות בחיבורי רשת שעברו ניצול יתר.
  • מיצוי משאבים: פודים או צמתים ספציפיים מראים שימוש במעבד או בזיכרון גבוה משמעותית בהשוואה לשאר ה-Fleet.
  • דפוסי חוסר איזון בתנועה:
    • חוסר איזון בכל Pod: תנועת הנתונים מגיעה רק לתת-קבוצה קטנה של Pods זמינים, למרות שכל ה-Pods מדווחים כבריאים ומוכנים.
    • חוסר איזון בכל צומת: צומת אחד או יותר מקבלים הרבה יותר מנות או בקשות מאחרים. הבעיה הזו נפוצה כשמשתמשים ב-externalTrafficPolicy: Local עם מיקום לא אחיד של Pod.
    • סשנים של לקוחות קבועים: כל הבקשות מלקוח יחיד עם נפח גבוה מנותבות באופן עקבי לאותו Pod של קצה עורפי.

אבחון באמצעות Cloud Monitoring

כדי לאשר את התסמינים האלה, אפשר להשתמש במדדים הבאים כדי להמחיש את דפוסי התנועה:

  • בשכבה 7 (Ingress/Gateway): משתמשים בפונקציות plot loadbalancing.googleapis.com/backend/request_count ו-קיבוץ לפי backend_target כדי להשוות בין נפחי הבקשות בשרתי קצה עורפיים שונים.

הסבר על סיבות נפוצות לחלוקת תנועה לא אחידה

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

זיקה לסשן גורמת לחלוקה לא אחידה

הבעיה הבאה מתרחשת כשמאזני עומסים עם זיקה לסשן (session affinity) מופעלת מעבירים באופן עקבי בקשות מאותו לקוח לאותו Pod של קצה עורפי. אם לקוח מסוים יוצר נפח גדול של תנועה, עומס היתר על ה-Pod הזה גורם לנקודה חמה שבה הוא מקבל עומס גדול משמעותית בהשוואה לאחרים, בעוד ש-Pods אחרים לא מנוצלים מספיק.

אפשר להגדיר זיקה לסשן (session affinity) באובייקטים של Kubernetes Service באמצעות השדה sessionAffinity.

אם הערך של sessionAffinity הוא ClientIP, השירות מוודא שכל החיבורים שמגיעים מאותה כתובת IP של לקוח מנותבים באופן עקבי לאותו Pod בקצה העורפי. כך מתקבלת זיקה אמיתית לסשן שמבוססת על כתובת ה-IP של הלקוח.

כשהערך של sessionAffinity מוגדר כ-None (התנהגות ברירת המחדל), מאזני עומסים בשכבה 4 בדרך כלל מחלקים את החיבורים באמצעות גיבוב של פרמטרים שונים ברשת, כמו 4-tuple (כתובת ה-IP של הלקוח, כתובת ה-IP של היעד, יציאת היעד, פרוטוקול) או 5-tuple (כולל יציאת המקור). הגיבוב הזה יכול לספק מידה מסוימת של "דביקות" בחיבורים, כי הוא מנתב באופן עקבי חיבורים עם ערכי טופל זהים לאותו שרת קצה עורפי. עם זאת, הוא לא מבטיח שכל החיבורים מכתובת IP ספציפית של לקוח תמיד ינותבו לאותו Pod אם רכיבים אחרים בטופל משתנים.

מידע נוסף זמין במאמר בנושא שיוך סשנים.

ב-GKE Gateway, ‏ GCPTrafficDistributionPolicy CRD מגדיר את הזיקה לסשן. מידע נוסף זמין במאמר הגדרת משאבי Gateway באמצעות מדיניות.

במאזני עומסים אזוריים חיצוניים של רשת להעברת סיגנל ללא שינוי, אפשר להשתמש בזיקה לסשן (session affinity) כדי לשמור על חיבור קבוע לקצה עורפי ספציפי. עם זאת, חשוב לזכור שזיקה לסשן (session affinity) יכולה לגרום בעצמה לחלוקה לא אחידה אם חלק מהלקוחות יוצרים יותר תעבורת נתונים מאחרים.

מידע נוסף זמין במאמרים בנושא Session Affinity וסקירה כללית של איזון עומסים ברשת חיצונית מבוסס-שירות Backend.

בדוגמה הבאה מוצג מניפסט של שירות עם sessionAffinity: ClientIP:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: LoadBalancer
  sessionAffinity: ClientIP  # This can cause uneven distribution
  ports:
  -   port: 80
    targetPort: 8080
  selector:
    app: my-app

מאגרי חיבורים גורמים לחלוקה לא אחידה

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

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

כדי לצמצם את הבעיה של חלוקה לא אחידה שנגרמת מאיגום חיבורים, כדאי להטמיע אסטרטגיות ברמת האפליקציה או הלקוח:

  • הגדרת לקוחות לשימוש בכמה חיבורים: במקום להסתמך על חיבור יחיד לטווח ארוך, מגדירים את הלקוחות לפתוח ולנהל מאגר של כמה חיבורים למאזן העומסים. כך מאזן העומסים יכול לפזר ניסיונות חיבור חדשים בין ה-Pods הזמינים של ה-Backend, ולשפר את חלוקת התנועה הכוללת.

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

  • הטמעה של זמן להשלמת תהליך (connection draining) אגרסיבי של חיבורים: מוודאים שה-Pods מוגדרים לכיבוי מבוקר ולזמן להשלמת תהליך (connection draining). כשמבצעים סיום תקין של Pod (לדוגמה, במהלך פריסה או צמצום), מאזן העומסים צריך להפסיק לשלוח אליו חיבורים חדשים ולאפשר לחיבורים קיימים להסתיים או להתרוקן. כך התנועה עוברת בצורה חלקה יותר ל-Pods אחרים, ומונעים מצב שבו התנועה מתרכזת ב-Pods שמסיימים את הפעולה.

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

גיבוב של 5-Tuple גורם להפצה לא אחידה

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

כדי לפתור חוסר איזון שנובע מגיבוב, כדאי לשקול את האפשרויות הבאות:

  • שימוש באיזון עומסים בשכבה 7: שירותי GKE Ingress ו-Gateway פועלים ברמת הבקשה, ולכן הם יכולים להפיץ בקשות מלקוח יחיד בין כמה תרמילי backend.

  • התאמת התנהגות הלקוח: הגדרת לקוחות לשימוש בכמה חיבורים או במאגר גדול יותר של יציאות מקור.

התפלגות לא אחידה של Pods בין הצמתים גורמת להתפלגות לא אחידה

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

הבעיה הזו רלוונטית במיוחד כשמשתמשים ב-externalTrafficPolicy: Local.

הגדרות של מדיניות תנועה חיצונית גורמות לחלוקה לא אחידה

ההגדרה externalTrafficPolicy בשירות משפיעה על ניתוב התנועה.

  • אשכול: מאפשר למאזן העומסים להפיץ את התעבורה לכל צומת באשכול. מומלץ להשתמש בהגדרה Cluster כדי להשיג את החלוקה הכי אחידה בין כל הצמתים וה-Pods הזמינים.
  • Local: תנועת הגולשים מנותבת רק אל ה-Pods שפועלים באותו צומת שקיבל את תנועת הגולשים. אם לא מפזרים את ה-Pods באופן שווה בין הצמתים, יכול להיות שהחלוקה לא תהיה אחידה.

העדפת צומת גורמת לחלוקה לא אחידה

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

מוודאים שאין הצמדה של ה-Pods לצמתים ספציפיים.