במאמר הזה מוסבר איך לפתור בעיות שקשורות להפצה לא אחידה של תעבורה לשירותי Kubernetes.
איך מזהים תסמינים של חלוקת תנועה לא אחידה
חלוקה לא אחידה של תנועה, שנקראת לעיתים קרובות נקודות חמות, מתרחשת כשקבוצת משנה של Pods או צמתים מטפלת בכמות לא פרופורציונלית של עומס העבודה הכולל, בזמן שאחרים נשארים לא מנוצלים.
התסמינים הנפוצים כוללים:
- צווארי בקבוק בביצועים: יכול להיות שהמשתמשים יחוו פסק זמן לסירוגין, שגיאות HTTP 5xx או אובדן מנות בחיבורי רשת שעברו ניצול יתר.
- ניצול משאבים: פודים או צמתים ספציפיים מראים ניצול גבוה משמעותית של מעבד או זיכרון בהשוואה לשאר הצי.
- דפוסי חוסר איזון בתנועה:
- חוסר איזון בכל Pod: תנועת הנתונים מגיעה רק לתת-קבוצה קטנה של Pods זמינים, למרות שכל ה-Pods מדווחים כבריאים ומוכנים.
- חוסר איזון בכל צומת: צומת אחד או יותר מקבלים הרבה יותר מנות או בקשות מאחרים. הבעיה הזו נפוצה כשמשתמשים ב-
externalTrafficPolicy: Localעם מיקום לא אחיד של Pod. - סשנים של לקוחות קבועים: כל הבקשות מלקוח אחד עם נפח גבוה מנותבות באופן עקבי לאותו Pod בקצה העורפי.
אבחון באמצעות Cloud Monitoring
כדי לאשר את התסמינים האלה, אפשר להשתמש במדדים הבאים כדי להציג את דפוסי התנועה:
- בשכבה 7 (Ingress/Gateway): משתמשים בפונקציות plot
loadbalancing.googleapis.com/backend/request_countו-קיבוץ לפיbackend_targetכדי להשוות בין נפחי הבקשות בשרתי קצה עורפיים שונים.
הסבר על סיבות נפוצות לחלוקת תנועה לא אחידה
בקטע הזה מתוארות סיבות נפוצות לחלוקת תנועה לא אחידה לשירותי Kubernetes. חוסר האיזון הזה עלול לגרום לצווארי בקבוק בביצועים, לניצול יתר של משאבים בחלק מה-Pods ולזמינות מופחתת של האפליקציה. חלק מה-Pods מקבלים נפח תנועה גבוה בהרבה מאחרים, וחלק מקבלים נפח תנועה נמוך מאוד או לא מקבלים בכלל.
זיקה לסשן גורמת לחלוקה לא אחידה
הבעיה הבאה מתרחשת כשמאזני עומסים עם זיקה לסשן מופעלת, ומנתבים באופן עקבי בקשות מאותו לקוח לאותו Pod של קצה עורפי. אם לקוח מסוים יוצר נפח גדול של תנועה, העומס על ה-Pod הזה גדל, והוא הופך לנקודה חמה שבה העומס גבוה משמעותית בהשוואה ל-Pods אחרים, בעוד ש-Pods אחרים לא מנוצלים מספיק.
אפשר להגדיר זיקה לסשן (session affinity) באובייקטים של Kubernetes Service באמצעות השדה sessionAffinity.
כשהערך של sessionAffinity מוגדר כ-ClientIP, השירות מוודא שכל החיבורים שמגיעים מאותה כתובת ה-IP של הלקוח מנותבים באופן עקבי לאותו Pod לקצה העורפי. כך מתקבלת קרבה לסשן שמבוססת על כתובת ה-IP האמיתית של הלקוח.
כש-sessionAffinity מוגדר ל-None (פעולת ברירת המחדל), מאזני עומסים בשכבה 4 בדרך כלל מפיצים חיבורים באמצעות גיבוב (hash) של פרמטרים שונים של הרשת, כמו 4-tuple (כתובת ה-IP של הלקוח, כתובת ה-IP של היעד, יציאת היעד, פרוטוקול) או 5-tuple (כולל יציאת המקור). הגיבוב הזה יכול לספק מידה מסוימת של "דביקות" בחיבורים, כי הוא מנתב באופן עקבי חיבורים עם ערכי טופל זהים לאותו שרת קצה עורפי. עם זאת, הוא לא מבטיח שכל החיבורים מכתובת ה-IP של הלקוח תמיד יגיעו לאותו Pod אם רכיבים אחרים בטופל משתנים.
מידע נוסף זמין במאמר בנושא זיקה לסשן (session affinity).
ב-GKE Gateway, GCPTrafficDistributionPolicy CRD מגדיר את הזיקה לסשן. מידע נוסף זמין במאמר הגדרת משאבי Gateway באמצעות מדיניות.
במאזני עומסי רשת אזוריים חיצוניים להעברת סיגנל ללא שינוי, אתם יכולים להשתמש בזיקה לסשן (session affinity) כדי לשמור על החיבור לקצה עורפי ספציפי. עם זאת, חשוב לזכור שזיקה לסשן עלולה לגרום לחלוקה לא אחידה אם חלק מהלקוחות יוצרים יותר תנועה מאחרים.
מידע נוסף זמין במאמרים בנושא Session Affinity וסקירה כללית על איזון עומסים ברשת חיצונית מבוסס-שירות קצה עורפי.
בדוגמה הבאה מוצג מניפסט של שירות עם 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 הזמינים בעורף, ולשפר את חלוקת התנועה הכוללת.
סגירה ופתיחה מחדש של חיבורים באופן תקופתי: לאפליקציות ששומרות על חיבורים לטווח ארוך, צריך להגדיר אותן או את הלקוחות שלהן כך שיסגרו ויפתחו מחדש חיבורים באופן תקופתי. אמנם זה יוצר תקורה קלה של יצירת חיבור מחדש, אבל זה מספק למאזן העומסים הזדמנויות חדשות להפיץ ניסיונות חיבור עוקבים לפודים שונים של קצה עורפי, שפחות מנוצלים. הגישה הזו יעילה במיוחד לשירותים שבהם סיום החיבור והקמה מחדש שלו לא גורמים לשיבושים משמעותיים.
הטמעה של זמן להשלמת תהליך (connection draining) אגרסיבי של חיבורים: מוודאים שה-Pods מוגדרים לכיבוי מבוקר ולזמן להשלמת תהליך (connection draining) של חיבורים. כש-Pod מסתיים בצורה תקינה (לדוגמה, במהלך פריסה או הקטנה), מאזן העומסים אמור להפסיק לשלוח אליו חיבורים חדשים ולאפשר לחיבורים הקיימים להסתיים או להתרוקן. כך התנועה עוברת בצורה חלקה יותר ל-Pods אחרים, ונמנע מצב שבו התנועה מתרכזת ב-Pods שמסיימים את הפעולה.
ניהול אקטיבי של אופן החיבור יכול לעזור למאזני העומסים לפזר את התנועה בצורה אחידה יותר, גם בחיבורים ארוכי טווח.
גיבוב (hashing) של 5-Tuple גורם לחלוקה לא אחידה
זוהי פעולת ברירת המחדל של מאזני עומסים רבים בשכבה 4, כשלא מגדירים במפורש זיקה לסשן (session affinity). אם הרבה חיבורים מגיעים מאותו לקוח או משתמשים באותן קומבינציות של יציאות, התוצאה היא חלוקה לא אחידה.
כדי לפתור חוסר איזון שנגרם כתוצאה מגיבוב (hashing), כדאי:
שימוש באיזון עומסים בשכבה 7: GKE Ingress ו-Gateway פועלים ברמת הבקשה, ומאפשרים להם לפזר בקשות מלקוח יחיד בין כמה Pods לקצה העורפי.
התאמת התנהגות הלקוח: הגדרת הלקוחות לשימוש בכמה חיבורים או במאגר גדול יותר של יציאות מקור.
התפלגות לא אחידה של רצפי מודעות בין הצמתים גורמת להתפלגות לא אחידה
הבעיה הזו מתרחשת כשהפודים לא מפוזרים באופן שווה בין הצמתים, ומאזן העומסים לא משתמש באיזון עומסים מקורי בקונטיינר. צמתים עם יותר Pods מקבלים יותר תנועה, מה שעלול לגרום לעומס יתר בצמתים מסוימים ולניצול חלקי בצמתים אחרים.
הבעיה הזו רלוונטית במיוחד כשמשתמשים ב-externalTrafficPolicy: Local.
הגדרות של מדיניות תנועה חיצונית גורמות לחלוקה לא אחידה
ההגדרה externalTrafficPolicy בשירות משפיעה על ניתוב התנועה.
- אשכול: מאפשר למאזן העומסים להפיץ את התנועה לכל צומת באשכול. מומלץ להשתמש בהגדרה
Clusterכדי להשיג חלוקה אחידה ככל האפשר בין כל הצמתים וה-Pods הזמינים. - Local: התנועה מנותבת רק אל Pods שפועלים באותו צומת שקיבל את התנועה. אם לא מפזרים את ה-Pods באופן שווה בין הצמתים, יכול להיות שהחלוקה לא תהיה אחידה.
התאמה של צומת גורמת להפצה לא אחידה
שימוש בהעדפת צומת כדי להגביל את הפודים לקבוצת משנה של צמתים עלול לגרום לעומס יתר בצמתים האלה, במיוחד אם עומס העבודה לא מאוזן ביניהם.
חשוב לוודא שה-Pods לא מוצמדים לצמתים ספציפיים.