במאמר הזה מוסבר איך לצמצם את ההשפעה של כשלים בעבודות בצינורות גדולים של עיבוד נתונים באצווה. לכשלים בעומסי עבודה גדולים יש השפעה משמעותית במיוחד, כי נדרשים זמן וכסף כדי להתאושש מהם ולתקן אותם. ניסיון חוזר להפעיל את צינורות הנתונים האלה מההתחלה אם הם נכשלים הוא יקר מבחינת זמן וכסף.
כדי לצמצם את מספר הכשלים היקרים בצינורות להעברת נתונים באצווה, מומלץ לפעול לפי ההנחיות שבדף הזה. אי אפשר תמיד להימנע לחלוטין מרכיבים שנכשלו ומכשלים בצינורות עיבוד נתונים, ולכן הטכניקות שמוצגות כאן מתמקדות בשיפור העמידות, בהפחתת העלויות של כשלים ובפישוט תהליך הניפוי של כשלים וההבנה שלהם כשהם מתרחשים.
מידע על שיטות מומלצות כלליות לשימוש בפייפליין זמין במאמר שיטות מומלצות לשימוש בפייפליין ב-Dataflow.
הפעלת ניסויים קטנים למשימות גדולות
לפני שמריצים משימה גדולה באצווה, מריצים משימה אחת או יותר על קבוצת משנה של מערך הנתונים. הטכניקה הזו יכולה לספק אומדן עלויות ולעזור לזהות נקודות כשל פוטנציאליות.
אומדן עלויות
הפעלת ניסויים יכולה לספק הערכה של העלות המינימלית הכוללת של הפעלת העבודה. בדרך כלל, החישוב של עלות העבודה הוא cost of test
job*size(full dataset)/size(test dataset). בהתאם לצינור, העלות יכולה לגדול בצורה סופר-ליניארית או, לעיתים רחוקות יותר, בצורה סאב-ליניארית. עם זאת, השלב הזה לרוב מספק הערכה גסה טובה של עלות העבודה. אפשר גם לנסות גדלים שונים של נתוני קלט כדי לקבל אומדן טוב יותר של האופן שבו העלויות גדלות. המידע הזה יעזור לכם להחליט אם להמשיך להשתמש בצינור הקיים או לשנות את הארכיטקטורה שלו כדי להפחית את העלויות.
איתור נקודות כשל
הפעלת ניסויים יכולה לחשוף באגים, נקודות כשל פוטנציאליות או בעיות פוטנציאליות בהגדרות וביעילות. אפשר גם לבדוק מדדים אחרים של צינורות, כמו המדדים הבאים:
- אם צינור הנתונים משתמש כמעט בכל הזיכרון הזמין, יכול להיות שיופיעו חריגות של חוסר זיכרון (OOM) בעומס גבוה יותר או ברשומות גדולות במיוחד. יכול להיות שתצטרכו להקצות יותר זיכרון לעבודה הסופית כדי להימנע משגיאות OOM.
- אם יש ירידות בנפח התפוקה של צינור עיבוד הנתונים, כדאי לבדוק את היומנים של צינור עיבוד הנתונים כדי להבין למה. יכול להיות שתזהו רכיב תקוע או חלק ממערך הנתונים עם ביצועים גרועים במיוחד. אפשר לעבד את נקודות הנתונים האלה בנפרד, או להגדיר פסק זמן לעיבוד הרכיבים. מידע נוסף מופיע בקטע הגדרת פסק זמן לרשומות יקרות במאמר הזה.
- אם הביצועים של צינור עיבוד הנתונים גרועים בהרבה במשימה ב-Dataflow מאשר באופן מקומי, כדאי לבדוק את הלוגיקה של צינור עיבוד הנתונים כדי להבין למה. לדוגמה, אם אתם מקבלים את אותה תפוקה עם שמונה ליבות ב-Dataflow כמו עם ליבה אחת באופן מקומי, יכול להיות שהעבודה מוגבלת בגלל תחרות על משאב. אם הביצועים שלכם גרועים מהצפוי, כדאי לנסות אחת או יותר מהאפשרויות הבאות:
- להריץ עוד ניסויים עם הגדרות שונות של מכונות או תוכנות.
- בודקים באופן מקומי עם כמה ליבות בו-זמנית.
- כדאי לבדוק את הקוד כדי לזהות צווארי בקבוק פוטנציאליים כשמבצעים פריסה בהיקף נרחב.
אם יש המלצות לשיפור הביצועים של צינור עיבוד הנתונים ב-Dataflow, כדאי לפעול לפיהן.
שימוש בתורים של הודעות שלא ניתן להעביר כדי לטפל בנתונים לא תקינים ולא צפויים
לרוב, צינורות העיבוד מצליחים לעבד את רוב רכיבי הקלט, אבל נכשלים בעיבוד של קבוצת משנה קטנה של הקלט. יכול להיות שלא תזהו את הבעיה הזו כשמריצים ניסויים קטנים, כי הניסויים האלה בודקים רק קבוצת משנה של הקלט. כברירת מחדל, Dataflow מנסה לבצע מחדש את המשימות שנכשלו ארבע פעמים במצב אצווה ומספר בלתי מוגבל של פעמים במצב סטרימינג. במצב אצווה, אחרי שמגיעים למגבלת הניסיונות החוזרים, כל העבודה נכשלת. במצב סטרימינג, יכול להיות שההפעלה תיעצר לזמן בלתי מוגבל.
בהרבה משימות, אפשר להחריג את האלמנטים שנכשלו מצינור העיבוד ולהשלים את שאר המשימה באמצעות תור של הודעות שלא עברו עיבוד (dead-letter queue). תור ההודעות שלא נמסרו מעביר רשומות שנכשלו לפלט נפרד PCollection, שאפשר לנהל אותו בנפרד מהפלט הראשי. ההגדרה הזו מאפשרת לכם לעצב מדיניות עבור הרשומות האלה. לדוגמה, אפשר לכתוב אותם ל-Pub/Sub באופן ידני, לבדוק ולנקות אותם, ואז לעבד מחדש את הרשומות.
הרבה טרנספורמציות של Apache Beam כוללות תמיכה מובנית בתורי הודעות שלא ניתן למסור.
ב-Java, אפשר לגשת אליהם באמצעות אובייקט ErrorHandler. ב-Python, אפשר לגשת אליהם באמצעות ה-method with_exception_handling. לחלק מהטרנספורמציות יש דרכים מותאמות אישית להגדרת תורי הודעות שלא ניתן למסור, ואפשר לקרוא על כך במסמכי התיעוד של הטרנספורמציה. מידע נוסף מופיע במאמר שימוש בתורי הודעות שלא נמסרו לטיפול בשגיאות.
כדי לבדוק אם העבודה שלכם עומדת בקריטריונים ליצירת תור של הודעות שלא ניתן להעביר, אפשר לעיין בקטע מגבלות במסמך הזה.
מגבלות של תור הודעות שלא ניתן להעביר
בתרחישים הבאים, תור להודעות שלא ניתן להעביר לא יכול לעזור:
- כשלים במחזור החיים של עובד מלא או של
DoFn. אם העיבוד נכשל עבור כל העובד או החבילה, אי אפשר לתפוס את הכשל בתור של הודעות שלא ניתן להעביר. לדוגמה, אם צינור העברת הנתונים נתקל בחריגה של חוסר זיכרון (OOM), כל המשימות הפעילות במכונה הווירטואלית נכשלות ומבוצע ניסיון חוזר להפעיל אותן, בלי לשלוח משהו לתור של הודעות שלא ניתן להעביר. - שילובים או צבירות אחרות. אם צינור הנתונים מבצע חישובים שדורשים שכל רכיבי הקלט יהיו נוכחים ויעברו עיבוד כחלק מהתוצאה, צריך להיזהר כשמשתמשים בתור של הודעות שלא נמסרו לפני השלב הזה. השימוש בתור הודעות שלא ניתן להעביר מוציא חלק מנתוני הקלט מהתוצאה. הוספה של תור הודעות שלא ניתן למסור עשויה להוביל לפשרה בין נכונות לבין עמידות בפני תקלות.
- כשלים בנתיב של תור ההודעות המתות. אם רכיב נכשל בזמן שהוא נשלח ליעד של תור הודעות שלא ניתן למסור, יכול להיות שכל צינור הנתונים ייכשל.
כדי להימנע מכשל כזה, כדאי לשמור על לוגיקה בסיסית ככל האפשר בתור להודעות שלא ניתן להעביר. אפשר להוסיף שלב המתנה (ראו
wait class) כדי לוודא שהקלט הראשי יסתיים לפני שייכתבו הרכיבים של תור ההודעות שלא ניתן למסור. ההגדרה הזו עלולה לפגוע בביצועים ולגרום לעיכוב באיתותים של שגיאות מצינור הנתונים. - רכיבים שעברו שינוי חלקי. אם מוסיפים תור להודעות שלא ניתן להעביר באמצע הצינור, יכול להיות שהתור יוציא את הרכיב שעבר טרנספורמציה חלקית ולא תהיה לו גישה לרכיב המקורי. כתוצאה מכך, אי אפשר לנקות את הרכיב ולהריץ מחדש את צינור הנתונים עליו. במקום זאת, יכול להיות שתצטרכו להחיל לוגיקה שונה כדי ליצור קורלציה בין הפלט בתור להודעות שלא ניתן להעביר לבין הרכיב המקורי, או שתצטרכו לפרש ולעבד את הרכיב שעבר טרנספורמציה חלקית. יכול להיות שגם התוצאות יהיו לא עקביות. לדוגמה, אם רכיבים נשלחים בשני ענפים של צינור, וכל ענף שולח רכיבים שגורמים לחריגה לתור של הודעות שלא נמסרו, יכול להיות שרכיב קלט יגיע לאחד מהענפים, לשני הענפים, לשניהם או לאף אחד מהם.
פסק זמן לרשומות יקרות
יכול להיות שצינורות יפסיקו להגיב בזמן עיבוד של קבוצת משנה קטנה של רכיבים שהעלות שלהם גבוהה יותר או שהם הגיעו למגבלה שגורמת לחוסר תגובה, כמו מצב של חסימה הדדית. כדי לצמצם את הבעיה, חלק מהטרנספורמציות מאפשרות להגדיר פסק זמן ולגרום לכשל של רכיבים שהגיעו לפסק הזמן בכל רכיבי DoFn של קוד משתמש שנתקלים בבעיה הזו. לדוגמה, אפשר להשתמש בשיטה with_exception_handling של Python. כשמשתמשים בערכי timeout עם תור הודעות שלא ניתן להעביר, הצינור יכול להמשיך לעבד רכיבים תקינים ולהתקדם, ואפשר לעבד מחדש את הרכיבים היקרים בנפרד. התצורה הזו עלולה לפגוע בביצועים.
כדי לקבוע אילו פעולות צפויות לדרוש פסק זמן, מריצים ניסויים קטנים לפני שמפעילים את צינור הנתונים המלא.DoFn
הפעלת שינוי גודל אוטומטי אנכי
אם אתם לא בטוחים כמה זיכרון נדרש לעבודה שלכם או חושבים שיש סיכון שהזיכרון ייגמר, כדאי להפעיל את התכונה 'שינוי גודל אוטומטי אנכי'. התכונה הזו עוזרת למנוע כשלים של OOM כשצינורות פועלים בקנה מידה גדול יותר או כשהם נתקלים ברכיבים גדולים במיוחד.
יכול להיות שהתכונה 'שינוי אוטומטי של גודל הזיכרון' תגדיל את העלות של העבודה, והיא לא מונעת את כל הכשלים שקשורים לזיכרון. לכן, עדיין צריך לטפל בבעיות של צריכת זיכרון מוגזמת. התאמה אוטומטית לעומס (automatic scaling) גם מחייבת שימוש ב-Dataflow Prime, שיש לו מגבלות נוספות ומודל תמחור שונה.
שימוש בהרצה ספקולטיבית כדי להימנע מבעיות של תהליכים שמתעכבים
בצינורות להרצת משימות באצווה, אפשר להפעיל ביצוע ספקולטיבי, תכונה שמיועדת לצמצום ההשפעה של משימות שפועלות לאט או נתקעות. משימות איטיות או תקועות כאלה נקראות גם משימות שמתעכבות. התכונה הזו מפעילה משימות מיותרות או גיבויים של משימות שנמשכות יותר מדי זמן. המשימה הראשונה שמסתיימת משמשת, והמשימה השנייה מבוטלת. כך אפשר לשפר את זמן ההשלמה הכולל של צינור הנתונים.
ביצוע ספקולטיבי יכול לעזור להשלים צינורות מהר יותר על ידי מתן נתיב ביצוע חלופי לפריטי עבודה שחווים עיכובים בגלל מכונות עבודה איטיות או בעיות זמניות אחרות, כמו באגים לא דטרמיניסטיים, הגבלת קצב העברת נתונים או בעיות בקישוריות.
מגבלות ושיקולים
לפני שמפעילים ביצוע ספקולטיבי, כדאי לשים לב לנקודות הבאות:
- צינורות עיבוד נתונים של סטרימינג: אין תמיכה בהרצה ספקולטיבית של צינורות עיבוד נתונים של סטרימינג.
- שינוי פוטנציאלי בעלות: קשה להעריך את ההשפעה של התכונה הזו על העלות, כי קשה לחזות את התופעה של משימות שמתעכבות ואת הקצאת המשימות לגיבוי. לדוגמה, פריט עבודה של גיבוי צורך משאבים נוספים, ולכן יכול להגדיל את העלות. עם זאת, השלמתו מוקדם יותר יכולה להוביל לחיסכון במשאבים ולהפחתת העלות. בשני התרחישים, ההשפעה הכוללת צפויה להיות מינימלית.
- פריטי עבודה ארוכים ועקביים: יכול להיות שהביצוע הספקולטיבי לא יעזור באופן משמעותי לפריטי עבודה ארוכים ועקביים, כמו מקשי קיצור, כי הבעיה הבסיסית שגורמת להאטה עדיין תהיה קיימת.
מידע נוסף על משימות שמתעכבות בעבודות אצווה זמין במאמר פתרון בעיות של משימות שמתעכבות בעבודות אצווה.
הפעלת ביצוע ספקולטיבי
כדי להפעיל ביצוע ספקולטיבי, משתמשים באפשרות map_task_backup_mode Dataflow
service. יש שני מצבים:
Java
--dataflowServiceOptions=map_task_backup_mode=ON--dataflowServiceOptions=map_task_backup_mode=CAUTIOUS
Python / Go
--dataflow_service_options=map_task_backup_mode=ON--dataflow_service_options=map_task_backup_mode=CAUTIOUS
במצב ON, מתוזמנת משימת גיבוי אם זמן הריצה הצפוי של המשימה המקורית ארוך בכ-20% מזמן הריצה הצפוי של משימה חדשה.
במצב CAUTIOUS, מתוזמנת משימת גיבוי אם זמן הריצה הצפוי של המשימה המקורית ארוך בכ-70% מזמן הריצה הצפוי של משימה חדשה.
כדי לוודא שההרצה הספקולטיבית מופעלת, בודקים את ההודעות ביומן. מחפשים רשומות שבהן מוצגות משימות גיבוי שהופעלו. כך תוכלו לוודא שההפעלה הספקולטיבית מופעלת. כדי לראות את היומנים האלה, עוברים לחלונית Job Logs (יומני משימות) של צינור הנתונים (Jobs > בחירת המשימה > Logs (יומנים) > Job logs (יומני משימות)). הודעת היומן מופיעה כך:
Backup issued in step STEP_NAME. ADDITIONAL_INFORMATION.
פתרונות עקיפים לצינורות עיבוד נתונים שמועדים לכישלון
יש צינורות שמועדים במיוחד לפורענות. עדיף לטפל במקור השגיאות האלה, אבל כדי להפחית את העלות של הכשלים, אפשר לשקול את האפשרויות הבאות.
יצירת תוצאות ביניים
יכול להיות שיהיו צינורות עם טרנספורמציות יקרות במיוחד שמשפיעות על זמן הביצוע של הצינור. כשלים בצינורות אחרי הטרנספורמציה הזו עלולים להיות בעייתיים במיוחד, כי כל העבודה שכבר הושלמה תאבד. כדי להימנע מהתרחיש הזה, כדאי לכתוב את נתוני הביניים PCollections שנוצרו על ידי שלבים יקרים ל-sink כמו Cloud Storage. ההגדרה הזו מפחיתה את העלות של כשל. כדאי לשקול את היתרון הזה מול העלות של פעולת הכתיבה הנוספת. אפשר להשתמש בתוצאה המגובה באחת מהדרכים הבאות:
- מפצלים את צינור עיבוד הנתונים המקורי לשני צינורות עיבוד נתונים: אחד שכותב את התוצאה הזמנית ואחד שקורא אותה.
- רק אם הצינור נכשל, המערכת קוראת את התוצאות מהמקור המקורי ומהאוסף הזמני שנוצר, ומיישרת אותן.
כדי לוודא שהחומרים האלה נכתבים לפני עיבוד נוסף, מוסיפים שלב המתנה (ראו wait
class) לפני כל שלבי העיבוד הבאים.