פתרון בעיות במינוי שליפה

במאמר הזה מפורטים כמה טיפים נפוצים לפתרון בעיות במינויי משיכה ב-Pub/Sub. מידע נוסף על מינויי משיכה זמין במדריך למנויי משיכה.

כדי לעקוב ביעילות אחרי המינוי ל-Pub/Sub, מומלץ קודם לבדוק את ציון התקינות של זמן האחזור של המסירה (subscription/delivery_latency_health_score) כדי לבדוק אילו גורמים יכולים לתרום לזמן אחזור בלתי צפוי או מוגבר.

הגיל של ההודעה הישנה ביותר שלא אושרה ממשיך לעלות

המדד oldest_unacked_message_age הוא מדד קריטי למעקב אחרי התקינות של מינויים ב-Pub/Sub. הוא מודד את הגיל, בשניות, של ההודעה הישנה ביותר בצבר ההודעות של מינוי, שעדיין לא אושרה (acked) על ידי מנוי. המדד הזה מספק תובנות חשובות לגבי עיכובים או צווארי בקבוק אפשריים בעיבוד.

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

אלה כמה מהבעיות הנפוצות בצבר המשימות שאפשר לבדוק:

בעיות בהגדרות הלקוח

כשגם המדד oldest_unacked_message_age וגם המדד num_undelivered_messages עולים בו-זמנית, יכול להיות שהמנויים לא עומדים בקצב של נפח ההודעות. במצב כזה, כדאי להתמקד בחקירה ברכיבים של המנוי:

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

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

  • מגבלות מכסה: ודאו שלא חרגתם ממכסות Pub/Sub או ממגבלות שהוגדרו על ידי שירות האירוח שלכם. אם המנויים מתארחים ב- Google Cloud, כדאי לבדוק את המכסות של המשאבים ב-Compute Engine או ב-GKE כדי למנוע צווארי בקבוק פוטנציאליים.

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

כשאפליקציה רשומה שולחת אישור שלילי (nack) על הודעה, זה מאותת ל-Pub/Sub שההודעה לא עובדה בהצלחה. לאחר מכן, Pub/Sub מנסה להעביר מחדש את אותה הודעה. שליחה חוזרת של nack להודעה מובילה לכפילויות, ועלולה לגרום לעיכוב משמעותי במסירת ההודעה.

חשוב לזכור שגם אם שולחים nack להודעה, לא בטוח שבמשיכה הבאה תתקבל הודעה אחרת. יכול להיות שמדיניות ההעברה החוזרת של Pub/Sub תמשיך להעביר מחדש הודעות שלא אושרו לפני הודעות חדשות. לכן, אל תסתמכו על nack כשיטה לסינון או לדילוג על הודעות ספציפיות. במקום זאת, הגדירו מדיניות ניסיון חוזר, רצוי השהיה מעריכית לפני ניסיון חוזר (exponential backoff), כדי להשהות הודעות ספציפיות שסביר להניח שניתן יהיה לעבד אותן מאוחר יותר, אבל נדרש קצת יותר זמן לפני השליחה החוזרת.

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

זמן אחזור ארוך של מסירה

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

אין מספיק מנויים

אם אתם משתמשים ב-StreamingPull, כדי לשמור על זמן אחזור נמוך, כדאי להשאיר כמה חיבורי StreamingPull פתוחים למינוי. בלי חיבורים פעילים של אפליקציות רשומות, מערכת Pub/Sub לא יכולה להעביר הודעות באופן מיידי. אם יש רק שידור אחד, הוא יכול להיות נקודת כשל בודדת, מה שמגדיל את הסיכון לעיכובים. המדד subscription/open_streaming_pulls מאפשר לראות את מספר החיבורים הפעילים לסטרימינג. כדאי להשתמש בזה כדי לוודא שיש לכם מספיק שיחות כדי לטפל בהודעות הנכנסות.

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

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

בעיות בהגדרות הלקוח

בעיות בהגדרות הלקוח

צבר משימות גדול

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

מפתחות הזמנה ומסירה פעם אחת בדיוק

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

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

הגדלת נפח ההודעות

עלייה פתאומית בגודל ההודעה עלולה להאריך את זמן ההעברה בין Pub/Sub לבין הלקוח, ולהאט את זמן העיבוד של ההודעות בצד הלקוח.

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

הודעות חסרות

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

הפצת הודעות במינויים ל-Pub/Sub עם כמה צרכנים

ב-Pub/Sub, יכול להיות שההודעות יופצו באופן לא שווה בין הצרכנים באותו מינוי. ‫Pub/Sub מבצע איזון עומסים של הודעות בין כל הלקוחות הפעילים, אבל המטרה העיקרית היא למקסם את תפוקת העיבוד הכוללת של ההודעות ולצמצם את הצבר, ולא להבטיח חלוקה שווה לחלוטין. המערכת מפנה באופן דינמי יותר הודעות לצרכנים שמפגינים קיבולת גבוהה יותר – אלה שמאשרים הודעות במהירות ולא מוגבלים על ידי הגדרות בקרת הזרימה שלהם. צרכנים שמעבדים הודעות במהירויות שונות או פועלים בתנאים שונים (למשל, זמינות משאבים, זמן אחזור ברשת) כנראה יטפלו בנפחים שונים של הודעות. בדרך כלל, צרכנים מהירים יותר שמגיבים מהר יותר יקבלו ויעבדו חלק גדול יותר מעומס ההודעות.

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

חשוב לזכור שיכול להיות שהודעות כבר נשלחו ללקוחות, וצבר של הודעות שלא אושרו לא בהכרח אומר שתקבלו את ההודעות האלה בבקשת המשיכה הבאה. חשוב לזכור שצרכן יכול להיות מישהו שמשתמש במשיכה במסוף Google Cloud או ב-Google Cloud CLI, או מפעיל מנוי בהתאמה אישית באופן מקומי כדי לבדוק הודעות.

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

אם צרכן לא מאשר הודעה לפני המועד האחרון לאישור, או אם הוא שולח אישור שלילי (NACK) להודעה, Pub/Sub ינסה לשלוח אותה מחדש. אפשר לבצע את ניסיון השליחה החוזרת לכל צרכן פעיל במינוי, לא בהכרח לזה שקיבל אותו בהתחלה. לכן, יכול להיות שמזהה הודעה מסוים יימסר לכמה צרכנים שונים שמחוברים למינוי במהלך משך החיים שלו, ושהם ינסו לעבד אותו, עד שאחד מהם יאשר אותו בהצלחה.

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

סינון לפי המינוי

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

שימוש באפשרות returnImmediately

אם הלקוח משתמש ב-Pull אונרי, בודקים אם השדה returnImmediately מוגדר כ-true. זהו שדה שהוצא משימוש, שאומר לשירות Pub/Sub להגיב לבקשת המשיכה באופן מיידי, גם אם היא חוזרת ללא הודעות. כתוצאה מכך, בקשות משיכה יכולות להחזיר 0 הודעות גם כשיש צבר משימות.

בעיות בהגדרות הלקוח

אם אתם משתמשים בספריית הלקוח של Java ומאתחלים את המנוי באמצעות ערוץ gRPC בהתאמה אישית באמצעות השיטה setChannelProvider(), ודאו שההגדרה של maxInboundMessageSize היא לפחות 20MB (תואמת לערך ברירת המחדל של הספרייה) כשאתם יוצרים את TransportChannelProvider. כשהערך הזה קטן מ-10MB, הודעות שגדולות מ-maxInboundMessageSize לא יתקבלו כמו שצריך. כמה שיטות נפוצות לקביעת ההגדרה הזו הן InstantiatingGrpcChannelProvider.Builder.setMaxInboundMessageSize() ו-ManagedChannelBuilder.maxInboundMessageSize().

טיפול בכפילויות

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

  • העברה חוזרת. לקוח אישר הודעה באופן שלילי או שתוקף המועד האחרון לאישור פג. זו התנהגות רגילה.

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

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

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

מועדים אחרונים לאישור שחלפו

שכפול הודעות ב-Pub/Sub מתרחש לעיתים קרובות כשמנויים לא יכולים לאשר הודעות במסגרת המועד האחרון לאישור. כתוצאה מכך, ההודעות נשלחות שוב, ונוצר רושם של כפילויות. אפשר למדוד את שיעור המנויים שמפספסים את המועד האחרון לאישור באמצעות המדד subscription/expired_ack_deadlines_count. איך עוקבים אחרי המועד האחרון לאישור

כדי להפחית את שיעור הכפילויות, אפשר להאריך את המועדים האחרונים לשליחת הודעות.

  • ספריות הלקוח מטפלות בהארכת המועד האחרון באופן אוטומטי, אבל יש מגבלות ברירת מחדל על המועד האחרון המקסימלי להארכה שאפשר להגדיר.
  • אם אתם יוצרים ספריית לקוח משלכם, השתמשו ב-method‏ modifyAckDeadline כדי להאריך את המועד האחרון לאישור.

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

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

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

אילוץ ניסיונות חוזרים

כדי לאלץ את Pub/Sub לנסות שוב לשלוח הודעה, שולחים בקשת nack. אם אתם לא משתמשים בספריות הלקוח ברמה הגבוהה, שלחו בקשת modifyAckDeadline עם ackDeadlineSeconds שמוגדר ל-0.

מפתחות להזמנה

כש-Pub/Sub שולח מחדש הודעה עם מפתח סדר, הוא שולח מחדש גם את כל ההודעות הבאות עם אותו מפתח סדר, גם אם הן אושרו בעבר. הפעולה הזו מתבצעת כדי לשמור על הסדר של הרצף. עם זאת, אין ערובה לכך שהודעות תלויות יישלחו רק אחרי אישור קבלה מוצלח של הודעות קודמות ברצף.

המנוי שולח אישור שלילי (NACK) על ההודעות

המנוי שולח nack להודעות.

פעולות דילוג

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

ביטול כפילויות במורד הזרם

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

פתרון בעיות במינוי StreamingPull

הקשר בין מדד זמן האחזור של הבקשה לבין זמן האחזור של המסירה מקצה לקצה

ב-StreamingPull, המדד serviceruntime.googleapis.com/api/request_latencies מייצג את משך הזמן שבו הסטרימינג פתוח. המדד הזה לא עוזר לקבוע את זמן האחזור של המסירה מקצה לקצה.

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

חיבורי StreamingPull נסגרים עם סטטוס שונה מ-OK

הסטרימינג של StreamingPull תמיד נסגר עם סטטוס שאינו OK. בניגוד לסטטוס שגיאה של RPCs מסוג unary, הסטטוס הזה של StreamingPull רק מציין שהחיבור של הסטרימינג נותק. הבקשות לא נכשלות. לכן, למרות ששיעור השגיאות ב-StreamingPull API עשוי להיראות מפתיע (100%), ההתנהגות הזו היא מכוונת.

מכיוון שסטרימינג של StreamingPull תמיד נסגר עם שגיאה, לא כדאי לבדוק את מדדי סיום הסטרימינג בזמן אבחון השגיאות. במקום זאת, התמקדו במדד התגובה של StreamingPull‏ subscription/streaming_pull_response_count, מקובץ לפי response_code או response_class.

חפשו את השגיאות הבאות:

  • שגיאות מסוג Failed precondition יכולות להתרחש אם יש הודעות בצבר המשימות של המינוי שמוצפנות באמצעות מפתח Cloud KMS מושבת. כדי להמשיך למשוך, צריך לשחזר את הגישה למפתח.

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

  • שגיאות Not found יכולות להתרחש כשהמינוי נמחק או אם הוא לא היה קיים מלכתחילה. המקרה השני קורה אם סיפקתם נתיב מינוי לא חוקי.

הפניות נוספות