הצרכניה והחשיבות של שרידות אפליקציות

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

מקור: flickr, cc-by Andrea_44

ביום שישי שעבר, בשעה 9 בבוקר, ממש כשהתחלתי לפרוק את המוצרים מהעגלה למסוע של הקופאית בסופר, התחילו המסופים של הקופות אחד אחרי השני לקרוס וקול הצפצוף של קריאות הברקוד נדם. הקופאיות ניסו לאתחל את המסופים – אבל זה לא עזר והתור והלחץ של הקונים (יום שישי יום קצר) התחילו לגעוש.

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

בלי פאניקה

מנהל הסופר ניסה להתקשר למרכז התמיכה ולתאר להם את הבעיה, כשהמידע הטכני המקסימלי שהוא יכל למסור לאותה מרכזנית זו הודעה הזויה שאומרת: Failed to login due to transaction abortion, או משהון בסגנון. טקסט שלדעתי גם למפתח הראשי של האפליקציה לא היה אומר הרבה.

האפשרות לבקש ממנהל הסופר לייצר קבצי Minidump ולשלוח למרכז הבקרה לא היתה ריאלית. כמובן שלהגיד למנהל הסופר שכעת שולחים לו קבצי symbols של הגרסה שרצה אצלו ושיוריד בבקשה מה-MSDN את ה-windbg ויתחיל לדבג את האפליקציה (זה טוב להדגמות עם תוכנות קטנות) זה גם לא ממש אפשרות.

כמו כן, סביר להניח שגם אם היו מנסים להכריז ברמקול של הסופר ולחפש תוכניתן בקהל, לא היו מקבלים עזרה אלא עצות וחוות דעת על למה צריך לכתוב את כל האפליקציה מחדש, למה כדאי לעבור לענן, להחליף לאנדרואיד, MVC4, Silverlight 5 או Spring. לא משנה כמה מוטיבציה היו מנסים ליצור אצל מנהל הסופר על ידי משפטים כדוגמת “עתיד הסופר בידך, אין אף אחד מאחוריך!!!” – האפשרות להמשיך את יום הקניות כסדרו תלויה אך ורק ביכולות ה-Recoverability של האפליקציה.

כל אפליקציה יכולה לקרוס

חשוב להבין שכל אפליקציה יכולה לקרוס, אם זה עקב בעיית חומרה או בעיית תוכנה. במטוסי נוסעים ישנם, ברוב המקרים, מספר מחשבים המיועדים עבור אותה משימה, המשמשים כגיבוי אחד לשני. אבל אצלנו בסופר בנס ציונה, לא נראה לי שזה המצב. אינני יודע למה לפתע קרסו כל העמדות, יכול להיות שהארכיטקט של המערכת לא לקח בחשבון אפשרות של נתק בין ה-Clients ל-Servers, או שהאפשרות שה-Server יקרוס לא עלתה בתכנון והמערכת לא תוכננה כ-Occasionally Connected Systems Architecture. יכול להיות גם שהמערכת תוכננה כ-Occasionally Connected Systems Architecture אבל הפצה של Poison Message ל-Client שאין נגדו הגנה, גרמה לשיתוק של כל העמדות.

דוגמא ל-Poison Message הינה עדכון של פרי חדש (לדוגמה ספוטה שחורה) בטבלת התמונות של הפירות עם תמונה בגודל 0 שגורמת ל-Exception.

הספותה השחורה הינה פרי רעיל כל עוד איננה בשלה כשהיא בשלה ניתן לייצר ממנה עוגות שוקולד מדהימות. cc-by quinn.anya

מרחב המקורות ל-Malfunction במערכת Client Server של 24 קופות, שכל הזמן מעדכנות נתונים בשרת וכל הזמן נדחפים אליהן נתונים חדשים (כגון מבצעים של יום שישי), כמעט ולא יכול להיות אפס. עם הזמן, כמות המידע שנצברת ומשתנה במערכת, גורמת למצבים שלא תוכננו כגון שאילתת Select בהצבה למשתנה שאמורה להחזיר רק ערך אחד, אך מחזירה יותר ואז ה-Stored Procedure קורס, או בעיות של Buffer Overflow, בעיות של Race Condition שנוצר עקב שילוב של כמויות גדולות של מידע ועוד.

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

ישנו פיתרון מובנה לחלק מסוים מהבעיות בתוך מנגנון ה-Application Recovery and Restart ומנגנון ה-Windows Error Reporting (ניתן למצא עליו פרטים באתר MSDN), אך הפתרון הינו חלקי ולא היה עונה על בעייה שבגינה התוכנה בקופות לא קרסה ולא הגיעה למצב של Second chance exception. במקרה המדובר, המערכת ברוב העמדות אפילו לא נתקעה, אלא פשוט הפסיקה לקבל סריקות ברקוד חדשות. יכול להיות מצב שרק תת המנגנון של בחירת פירות לא עובד, אך זה הופך את המערכת לבלתי שמישה לחלוטין.

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

ברמה של ניהול מוצר יש מספר עקרונות לתמיכה ב-Recoverability

  1. זמן Recovery ועליה מחדש מינימלי – במשך השעה הזו שהקופות לא פעלו עשרות עגלות של מוצרים ננטשו על ידי קונים ממורמרים. כך שכמובן שאין זמן ל-Production Debugging.
  2. אפשרות ניטור הבעיה – מיועד למקרים קיצוניים בהם Restart של אפליקציה לא עוזר. בדרך כלל כאשר הבעיה נגרמת על ידי מצב סטטי כמו בעיית חומרה (דוגמת דיסק קשיח מלא), או בעיית תוכנה מסוג של Poison Message, אפשרות לפתוח חלון של קופאי בכיר המציג את הבעיה מגובה תמיד באפשרות לפתוח קובץ לוג באמצעות Notepad ולהבין משם מה הבעיה.
  3. החזרת האפליקציה במדויק ל-State הקודם – בזמן ההמתנה, על מנת ליצור לפחות תחושה של התקדמות, הערימו הלקוחות ערמות על גבי ערמות של מוצרים על המסוע. לפיכך, האפשרות שאחרי Reset של עמדה, יצטרכו להתחיל חשבון שהוא כבר לפני סיום מההתחלה – איננה ריאלית במקרה הזה מכיוון שלהתחיל להחזיר את המוצרים מהעגלה אל הקופה יכול לייצר מצב שבו הלקוחות מפחדים שיחויבו פעמים. בכל מקרה, יש לשים לב שבוצעו מספר אתחולים של האפליקציה לפני שהיא חזרה לעבוד ולפיכך איפוס ה-State, ששמור לצרכי המשך עבודה אחרי כל עליה הינו שגיאה לוגית. אחרי שהאפליקציה חזרה לסורה, למשתמש צריכה להיות האופציה לבחור את ה-State של ה-Recovery המתאים לו מבין כל הסשנים הקודמים.
  4. העברת Session בין תחנות – מנגנון שמירת ה-Session צריך לתמוך במצב שלאפשר לעבוד בעמדה אחרת במקרה ועמדה התקלקלה לגמרי.
  5. אפשרות לעשות roll back למידע חדש שיכול לגרום לתקלה – יכול להיות שזה מידע שיושב ב-Cache המקומי או מידע שנמצא בשרת ואינו מאפשר למערכות להמשיך לעבוד.

עקרונות ארכיטקטונים לתוכנה שתיתמוך ב-Recoverability

הפרדה בין State לפונקציונליות – מבחינה ארכיטקטונית על מנת לתמוך ב-Recoverability של האפליקציה יש להקפיד על הפרדה בין state לפונקציונליות.

state שמופרד מהלוגיקה יכול להישמר באופן תדיר לצרכי recovery על ידי מגנוני הסיראליזציה הקיימים כמעט בכל השפות והטכנולוגיות (לדוגמא: מנגונוני ה-Shelve או ה-Pickle ב-Python). האויב הגדול ביותר של ההפרדה בין state לפונקציונליות הוא מימוש לא נכון של Class Properties. לדוגמה: Get Accessor שמשנה את ה-state של ה-class ו-Set Accessor של Property, שכשקוראים לו מספר פעמים עם אותו הערך ה-State של ה-Class לא נשאר אותו הדבר.

שמירה מתמדת על ה-State של האפליקציה לצרכי שחזור המצב

ה-state השמור לא צריך להיות רק חלק ממסד הנתונים של האפליקציה אלא גם כגיבוי חיצוני כדוגמת קובץ או שימוש ב-NoSQL db מסוג Document. יש לקחת בחשבון תסריטים שונים לדוגמת מצב שבו ה-State ששמור הינו מינימלי, כגון שלב עריכת החשבון של לקוח (במקרה הזה רוב הנתונים כבר נשמרו במסד הנתונים).

מקור: צביקה פאר

 תיכנון המערכת כ-Occasionally Connected Systems Architecture

מערכת שתוכננה כ-Occasionally Connected Systems Architecture, על אף היותה מורכבת יותר ממערכת שהינה Client-Server בסיסית, מאפשרת יכולות שרידות ושחזור גבוהות יותר באופן משמעותי. במצב כמו הדוגמה שלנו שהשרת התקלקל, אפשר היה לסיים בשקט את הפעילות תוך כדי שמירה של כל הפרטים למסד נתונים מקומי, אשר יסונכרן בהמשך עם מסד הנתונים המרכזי, אם וכאשר תשוב הפעילות לסדרה.

ביצוע logging

logging נכון ומפורט, נטול מידע בלתי רלוונטי ומידע מיותר שחוזר על עצמו (כגון להפציץ את הלוג בהודעות מחזוריות תקינות) הוא המצב האידיאלי. לא פעם נתקלתי ב-לוג בגודל של כמה גי’גהבייט שמכיל מיליוני הודעות :Message was send או Second Chance Exception Occurred מבלי שום Stack Trace. הכי חביב זה הודעות Wrong Value בברירת המחדל של Switch Case מבלי לציין מהו הערך הלא נכון שהתקבל.

זמן עליה \ ירידה של המערכת סביר

לא צריך להטעין את כל המידע שבעולם ל-cache בזמן עליית המערכת – אפשר גם לטעון מידע ב-JIT.

כלי ניהול

רצוי שכל הניהול של האפליקציה המאפשרים בחינה של ה-Log וניהול של מסד הנתונים (כולל מחיקה של Poision Messages) לא יהיו חלק מהאפליקציה לא של ה-Client ולא של ה-Server, אלא כלים נפרדים לחלוטין שאפשר להפעיל אותם בלי תלות בכלים האחרים.

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

כתב אורח

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

הגב

הגב ראשון!

avatar
Photo and Image Files
 
 
 
Audio and Video Files
 
 
 
Other File Types
 
 
 

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

wpDiscuz

תגיות לכתבה: