על Circuit Breakers ויציבות של מערכות מבוזרות

דמיינו 2 חנויות מכולת כמעט זהות: "המכולת של שמואל" ו"המכולת של הלל".

בשתי חנויות המכולת יש מוצרים איכותיים שאתם אוהבים, מוזיקה טובה מתנגנת, השירות מצוין, הן פתוחות 24/7, והמחירים – הוגנים. אתם אוהבים את המכולות הללו, ואתם אוהבים לקנות בהן.

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

במכולת של הלל – המצב הפוך. הם מוכנים לכך שלא יהיו מוצרים מסוימים זמינים. הם קוראים למצב הזה partial service או degraded service (הם קצת גיקים עם המונחים שלהם). המכולת פתוחה 24/7 למעט מקרים נדירים בהם הם סוגרים אותה (כאשר הלל צריך לצאת לאיזה סידור ואין לו מחליף), אבל כאשר אני הולך לקנות משהו – ייתכן ואחזור ללא קוטג' הביתה. לפעמים לא אכפת לי, אבל לפעמים זה מבאס. אם זה ממש חשוב לי אפילו אקפוץ למכולת אחרת להביא את הקוטג'. אבל בגלל שאני אוהב את החוויה במכולת – אני עדיין אחזור אליה בקנייה הבאה.
במקום לדאוג ל"אפס חוסרים במלאי", החבר'ה של הלל עסוקים בכך שחוסר של מוצר מסוים במלאי – לא יגרום למכולת להיסגר מעצמה. זה מאוד מוזר אבל הם מספרים שאם לא יעשו שום דבר, מחסור בטונה פתאום יגרום למכולת להסגר מעצמה. גיקים – אמרנו כבר?

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

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

בצורה בלתי מובנת, האינטואיציה של רובנו היא ללכת בגישה הראשונה.
הסבר אחד הוא שגישה זו ישימה בעת שהמערכת עוד קטנה – וקשה לנו להתרגל לרעיון שכללי המשחק השתנו עם הזמן.
הסבר שני הוא שאנו "מהנדסים באופי" שחושבים מנקודת מבט של "המוצר שאו בנינו ויש לנו אחריות עליו" וקצת פחות מנקודת המבט של חווית השירות שמתקבלת בסוף. אם היינו צרכנים של המוצר – קרוב לוודאי שהיינו מעדיפים את חווית השימוש השנייה (בד"כ. ישנם כמובן גם מקרים בהם הראשונה עדיפה, למשל: בניתוח לב פתוח, לא היינו רוצים להתחיל ניתוח אם חסר משהו… 🙂 ).

Circuit Breakers

המנגנון הבסיסי המאפשר את מודל "המכולת של הלל" הוא ה Circuit Breaker.
לצורך הדיון אניח שמדובר במערכת בארכיטקטורת Micro-Services (בקיצור: MSA) והשירותים השונים הם הרזולוציה לבידוד בפני תקלות. ניתן לעשות אותו הדבר במערכת "מונוליטית", אם כי המשמעת העצמית הנדרשת היא לעתים מעט גבוהה יותר.

ה Circuit Breaker הוא מן Proxy לשירות מרוחק – אשר רק דרכו עושים את הקריאות. השירות המרוחק יכול להיות:
א. זמין
ב. לא זמין
ג. זמין – אך כושל (יש errors)
ד. זמין אבל אטי

אם ה Circuit Breaker מזהה שהשירות המרוחק אינו עובד כמו שצריך – הוא "יוצר נתק" (מטאפורה: פותח את המעגל) ולא מאפשר לקריאות נוספות לעבור. הפונקציות השונות מקבלות אינדיקציה על המצב הזה ופועלות כמיטב יכולתן לספק שירות חלקי – שעדיף על חוסר שירות.

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

מקורות: "דפוס העיצוב" של ה Circuit Breaker הוצג לראשונה ב 2007 ע"י מייקל נייגארד, בספר המצויין (!!): !Release It.
ב 2014 מרטין פאולר כתב פוסט בבלוג על דפוס העיצוב (הוא לא חידש שם, רק הסביר יותר פשוט), ומאז זהו ה reference המקובל.

המימוש הפנימי של ה Circuit Breaker הוא לרוב כמכונת מצבים פשוטה:

מקור: orgsync/stoplight (מימוש ברובי של Circuit Breaker)
  • המצב ההתחלתי הוא "מעגל סגור" (ירוק).
  • אם יש מספר מסוים של תקלות (מוצג בתרשים כ "fail") – עוברים למצב "אדום".
    • בד"כ לא מדובר בתקלה יחידה אלא threshold של סדרת תקלות. למשל: רצף של 5 exceptions, כאשר ה threshold הוא של 5.
  • במצב "אדום" – כל ניסיון קריאה לשירות המרוחק ייענה בערך החזרה מסוים (או Exception) מצדו של ה Circuit Breaker שאומר "תסתדרו בלי!" (כלומר: בלי השירות).
  • לאחר זמן מה (נניח: 120 שניות) של מצב אדום, ה circuit breaker יעבור למצב צהוב – ניסיון להחזיר שירות.
    • הוא יאפשר למספר נתון של קריאות לעבור לשירות המרוחק כדי לבדוק את התגובה. למשל: 10 קריאות. לכל שאר הקריאות הוא עדיין יחזיר את התשובה "תסתדרו בלי!".
    • אם ב 10 הקריאות הללו, הוא מזהה treshhold מסוים בעייתי, למשל: רצף של 3 exceptions מצד השירות המרוחק (לרוב ה threshold של המצב הצהוב הוא יותר מחמיר מזה של המצב הירוק) – הוא חוזר למצב אדום.
    • אחרת – הוא מחזיר את המערכת למצב ירוק.
כמו שאתם מבינים – יש המון וריאציות אפשריות של התנהגות של Circuit Breakers:
  • אפשר לשים thresholds שונים ומשונים. למשל, משהו שלא הזכרנו: שניסיונות חזרה למצב הצהוב יקרו בתדירות משתנה: יש גישה של המתנה של 2 דקות ואז כל 30 שניות (כאשר השירות המרוחק הוא חשוב) ויש גישה של להאריך את זמני הניסיון, למשל: פעם ראשונה 2 דקות, אח"כ 5 דקות, וכל פעם נוספת – 10 דקות (כאשר השירות המרוחק פחות חשוב ודווקא שגיאה ממנו היא לא נעימה).
  • כאשר circuit breaker מופעל – כנראה שתרצו שסוג של alert יעלה ל monitoring, הרי מדובר בהחלטה לתת שירות פחות טוב. מתי ואיך להעלות את ה alert – עניין לבחירה.
  • לעתים יש אפשרות של override ידני – אפשרות לקבע מצב ירוק/אדום/צהוב של ה circuit breaker בהתערבות ידנית.
  • אולי הכי חשוב: כיצד ה circuit breaker מאתר שגיאה של השירות המרוחק?
    • האם ע"י ניטור ה responses של ההודעות שחזרו מהשירות המרוחק (למשל: HTTP 5xx)?
    • האם ע"י ביצוע בדיקה יזומה (proactive) לשרת המרוחק (למשל: שליחת pinging או בדיקת health-check)?
    • אם מדובר על אטיות, ה circuit breaker יכול למדוד את מהירות החזרה של קריאות מהשרת המרוחק. אפשר להגיב לממוצע של קריאות אטיות, או לעתים להסתכל על אחוזון מסוים. למשל: אם 5% מהקריאות אטיות מ 10 שניות, אנו רוצים לנתק – מכיוון שזה אומר שירות גרוע למשתמש הקצה. האם מנתקים רק את הקריאות האטיות או את כולן?!
    • וכו'
תוכלו למצוא מספר מימושים שונים של Circuit Breakers, בכל שפת תכנות כמעט (לא ראיתי באסמבלי ;-)), אבל לא נדיר המקרה בהם תרצו לממש גם וריאציה משלכם – במידה ויש לכם מקרה חשוב שלא מטופל ע"י המימושים הזמינים.

לא נדיר גם מצב בו אתם משתמשים בכמה circuit breakers שונים בתוך המערכת. תלוי כמה גדולה ומורכבת היא.
ההתעסקות עם circuit breakers גם היא יכולה להיות משמעותית, וכדאי לשים לב ש:

  • אתם לא נסחפים לאזור ה over-optimization שאיננו משתלם מבחינת ההשקעה.
  • אתם יוצרים מערכת של circuit breaker שהיא מורכבת מדי לניטור ושליטה בזמן אירוע אמת ב Production (כאשר אתם לא יכולים לענות על שאלות כמו: "מדוע x התנתק"? או "אילו ניתוקים היו בזמן נתון").

אלו דוגמאות מהעולם האמיתי של ל Partial Service ניתן לתת? הנה כמה שאני נתקלתי בהן:

  • לוגים, לוגים, לוגים! בעם הייתה לנו מערכת עם שירות ירוד כמעט יומיים (!!) עד שהבנו שהיא נופלת כל הזמן כי הדיסק מלא ופעולות כתיבה ללוג נכשלות. אם כתיבה ללוג נכשלת – עדיף לא לכתוב לוגים, מאשר לגרום ל IO exceptions שמשבשים תהליכים שלמים במערכת.
    • בווריאציה אחרת מערכת מרוחקת לדיווח של בעיות (סוג של alerts) הגיבה ב latency של 4 שניות, וגרמה לשיבושים רבים בשירות שדיווח לה על בעיות זניחות, יחסית.
  • שירות ש"מצייר" מסלול נסיעה על המפה של החשבונית (בעולם המוניות). אם הוא לא זמין / מגיב היטב – שלח חשבוניות בלי ציור של המסלול, מה הבעיה?
  • שירות שמבצע סליקה של תשלומים. עדיף לשמור את סכום העסקה ולנסות לחייב כמה דקות מאוחר יותר (תחת סיכון של חיובים, עד סכום מסוים, ללא כיסוי) – מאשר לדחות על הסף את כל העסקאות, אפילו בפרק זמן קצר יחסית (כמה דקות).
  • וכו' וכו'

Throttling

עוד וריאציה דומה של Circuit Breaker היא מנגנון throttling ("להחזיק אצבע על הקשית כך שלא יהיה זרם חזק מדי").

למשל (מקרה אמיתי שנתקלתי בו): ידוע שיש שרת Backend מרוחק שאין לו יכולות scale. המערכת שלנו – עם scale משתנה. אם נפנה לשרת המרוחק בקצב גבוה מדי, הוא עלול להתרסק (לא רק "להגיב לאט") – מה שיפגע בחזרה, ובצורה מורגשת בשירות שלנו.

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

המנגנון הוא דיי פשוט (אתאר את המימוש הספציפי) – עוקבים אחר מספר הבקשות הפעילות לשרת המרוחק בעזרת distributed, non-blocking lock (קל יותר באנגלית) על בסיס רדיס: לפני קריאה לשרת המרוחק מנסים "לקבל" Lock – אם מצליחים – מבצעים את הקריאה. אם לא מצליחים (כי כבר יש 10 קריאות פתוחות) – מחזירים הודעת "תסתדרו בלי!" לפונקציה שביקשה את השירות, ונותנים לה לספק שירות חלקי.

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

TCP timeouts

עוד נקודה ששווה להזכיר היא ה timeouts שאנו קובעים לתקשורת.
Timeouts הם מנגנון הגנה ממעלה ראשונה: אם שרת מרוחק לא מגיב – לא נרצה לתקוע thread (או אפילו request) לאורך זמן. תסריט נפוץ הוא שירות אטי, שגורם לשירות שקורא לו גם להיות אטי (כי הוא עסוק בלהמתין), שגורם גם הוא לשירותים האחרים התלויים בו – להיות אטיים באותו האופן.

למרות ש TCP הוא "reliable protocol", גם לו יש תקלות: בעיקר התנתקויות. כאשר קצב הקריאות בין שירותים הולך גדל – אנו נחווה תקלות אלו יותר ויותר.

התנהגות נפוצה היא לספק אותו ה timeout ליצירת ה connection וביצוע הקריאה עצמה (פעולת "קריאה"). אבל:

  • פעולת ה connection היא פעולה פשוטה ומהירה – היא אורכת, באופן טיפוסי, שבריר של שנייה (בניכוי network latency).
  • פעולת הקריאה לרוב גורמת לשירות השני לעבוד: לקרוא מידע מבסיס הנתונים, לקרוא לשירותים אחרים, לבצע עבודת CPU משמעותית וכו. זמן מקובל לקריאה שכזו הוא כ 100ms וגם לא נדיר להיתקל במצב של 1000ms ויותר (שוב: בניכוי network latency).

לכן, אם נגדיר timeouts באופן הבא:

  • עבור פעולת ה connection של ה TCP – נגדיר timeout בסך ה: tolerable latency
  • עבור פעולת ה read של ה TCP – נגדיר timeout בסך: tolerable latency + tolerable server time

נוכל לצמצם בצורה מורגשת זמני המתנה מיותרים.

כמו כן, אם יש לנו timeout על connection – כדאי לשקול בחיוב פעולת retry מיידית.
ניתן להראות ש timeout קצר ליצירת connection + ביצוע retry יחיד – היא מדיניות שברוב המקרים תהיה עדיפה בהרבה על יצירת connection עם timeout ארוך.

הסבר (דרוש רקע תאורטי בעבודה של TCP): אם ההודעה על לחיצת היד השלישית של TCP אובדת – אין מנגנון (מלבד timeout) לדעת זו. בעיה זו במדעי-המחשב ידועה כבעיית הגנרלים, ומשמעותה שלא ניתן לייצר מנגנון אמין ל handshake. הפתרון של TCP הוא לבצע 3 קריאות handshake בתקווה שזו נקודת איזון טובה בין עלות (מספר הקריאות) / סיכון לכישלון.

אחד הנתונים הידועים ב AWS הוא ש latency בין AZs יכול להיות עד 10ms. אם מסתכלים על הנתונים עצמם רואים ש 10ms הוא לא ממוצע, אלא אירוע נדיר יחסית: בבדיקות שערך Matthew Barlocker (חברת Lucid Software) – הוא ראה שבאחוזון ה 99.85% מקבלים latency בין AZ של 3ms בלבד:

הערה: אמזון מתעדפת נמוך (de-prioritize) קריאות ICMP (פרוטוקול השליטה של TCP/IP, הכולל גם את פקודת ה ping) – ולכן לא כדאי להסתמך על Ping להערכת ה latency ב AWS.

מסקנה אפשרית אחת היא שסביר לקבוע TCP Timeout של 3ms כאשר ליצירת connection באותו ה AWS region.
על פעולות HTTP GET ניתן לשקול (תלוי במקרה) מדיניות דומה של מתן timeouts קצרים יחסית (יש לקחת בחשבון את זמן השרת + network latency) – עם אפשרות ל retry.

"Be Resilient" vs. "Fail Fast"

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

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

מדיניות טובה אחרת אומרת: Fail Fast – אם המערכת מזהה שגיאה או סבירות גבוהה לשגיאה, עליה "לשבור את הכלים באותו הרגע" – וכך יהיה קל יותר לאתר את התקלה. אם התקלה נגררת ונגררת – ה"שבר" צפוי להיות בשלב מאוחר יותר במערכת, בשלב שיהיה קשה מאוד להבין ממנו מה מקור הבעיה האמיתי (root cause).

כיצד 2 גישות חכמות אלו משתלבות זו עם זו בעולם של מערכות מבוזרות, השאופות ליציבות גבוהה?

למרות הסתירה הבסיסית, ניתן לשלב את שתי הגישות:

  • אם מזהים כשל שנראה שניתן "לספוג" – אפשר לבצע Alert Fast, בשאיפה שה Alert מספיק ברור ומשמעותי כדי שיהיה ניתן לנטר אותו ולטפל בו בזמן סביר.
  • אם מזהים כשל שנראה שלא ניתן "לספוג" אותו – זהו באמת מצב שכדאי לעשות Fail Fast.
פעמים רבות, מה שמתחיל כ"כשל חלקי" שניתן לספוג אותו – מתגלגל בהמשך לכשל משמעותי יותר שלא ניתן עוד לספוג ("כמות הופכת לאיכות"  – של הכשל). אם אתם בוחרים בכיוון של Alerts – כדאי שאלו יהיו Alerts שתוכלו, ואכן תתייחסו אליהם – בזמן סביר.

סיכום

בעוד שמערכת יחידה ("מונוליטית") מתעסקים באופטימיזציה של ה up-time (מדד ברור למדי) – במערכות מבוזרות, המציאות יכולה להיות מורכבת / גמישה ברבה.

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

היכולת של מערכת להימצא במצבים שונים של כשלים-חלקיים מוסיפה מורכבות למערכת – אך מאפשרת להגיע לזמינות (availability) גבוהה יותר כאשר מדובר במערכת מורכבת.
העצה של מרטין פאוולר ל MonolithFirst היא טובה בהיבט הזה: מערכת מבוזרת היא בהחלט מורכבת יותר – ומבחינת זמינות  משתלם לעבור למודל מבוזר רק כאשר כלל המערכת הגיע לסף מסוים של מורכבות.
זמינות גבוהה של מערכת מושגת לא רק על ידי תכנון נבון, אלא גם ע"י אימונים ושיפור תמידי.
Chaos Monkey, למשל, הוא כלי Open Source ש"יפיל" לכם בצורה יזומה אך אקראית שירותים (או שרתים) במערכת – כדי שתוכלו לבדוק את ההתמודדות שלכם, ולשפר את צורות התגובה שלכם לכישלון שכזה.
בשלב ראשון ניתן להפעיל אותו בסביבת בדיקות – בה נפילה היא למידה ללא נזק, ובהדרגה ניתן להתקדם לסביבות יותר ויותר מציאויתיות ומחייבות. אם אתם מסוגלים להפעיל אותו ב production, בשעות העומס שלכם, ולשרוד עם שירות סביר – אז אתם בליגה העולמית!
שיהיה בהצלחה!

על Performance Monitoring ו New Relic

New Relic (בקיצור NR) הוא כלי ה Application Performance Monitoring (בקיצור APM) מהמוערכים שזמינים בשוק היום.
Relic הוא שריד קדום, והשם New Relic נבחר כמעט כבדרך אגב: היזם (Lew Cirne) השתעשע בתוכנה שמוצאת צמדי-מלים המורכבות מהאותיות של שם המשתמש, ובעת רישום החברה זה השם שנבחר, כמעט באקראיות. מאז הוא נותר.NR הוא לא יחיד: יש את AppDynamics (שמכוון יותר ל Enterprise), או Nagios (פתרון Open Source) נפוץ למדי – ויש עוד רבים.

NR איננו זול: הוא עולה כ 100-150$ ל host לחודש. אם מנטרים כמה עשרות שרתים יכולים להגיע בקלות לכמה אלפי דולרים בחודש, אבל אנחנו (כמו עוד לקוחות רבים של פתרונות ה Premium) – החלטנו שזו השקעה משתלמת.

אנו ב Gett משתמשים ב NewRelic, ובכלי משלים בשם Graphite, שהוא יותר תשתית ל"הרכבה עצמית" של monitoring. יש גם את StackDriver. דיי נפוץ לראות ארגונים שמשתמשים ביותר מכלי אחד ל APM.

ל APM יש שני שימושים עיקריים:

ניטור בעיות ב production בזמן אמת
הרבה תקלות טכניות ניתן לזהות ע"י מדידת שיוניים בביצועי המערכת.
לעתים, לא נזרקות הודעות שגיאה חריגות, ושום Alerts מרכזי שכיוונתם ואתם מנטרים לא מזהה משהו חריג – אבל משהו רע קורה למערכת. לפני שהתקלה ממש משפיעה על המשתמשים – יש סימנים מקדימים: לעתים אלה יהיו spikes של עומס על המערכת, ולעתים דווקא ירידת עומס בלתי מוסברת: כמו צונאמי שמתחיל בירידת מפלס הים… וקצת אח"כ הוא מכה.
אם העסק שלכם מבוסס על זמינות המערכת, בוודאי תרצו לאתר את הסימנים המקדימים הללו – ולהגיב בהקדם.
שיפור ביצועי המערכת
מדי פעם, מחליטים שהגיע הזמן לשפר ביצועים. אולי בגלל feature חדש שמעמיס על המערכת מעבר לצפוי, ולעתים בגלל שהמערכת כבר "לא סוחבת" כפי שסחבה פעם (או שסתם נמאס לכם לשלם עשרות אלפי דולרים בחודש על Infrastructure).
NR (וכלים דומים) יכולים לספק במהירות ובקלות ניתוחים התחלתיים טובים לצווארי הבקבוק העיקריים במערכת. לפעמים הניתוח של NR כמו שהוא – מספיק בכדי להבין את השיפור המדויק שיש לבצע  (למשל: שאילתת SQL יעילה יותר), לעתים אחרות NR מצביע על אזור הבעיה, ואז מתחילים באיטרציות של ניסויים / הוספת monitors (לעתים ב new relic, ולעתים בכלים קרובים יותר לקוד) – עד לאיתור המדויק של הבעיה ומציאת הפתרון.

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

הטריגר לפוסט, אגב, הוא כוננות "Tier 1" שעשיתי השבוע. זו כוננות ב Gett לקבל טלפון אם יש Crisis במערכת, באחת מהמדינות, לבצע ניטור ראשוני ולהעיר את הצוות שיטפל במשבר. New Relic הוא כנראה המקום הראשון שאבדוק בו, על מה המהומה. בלילות כאלו – זהו חבר קרוב.

צורת העבודה של New Relic

New Relic תומך בסביבות קוד מסוימות:

  • רובי
  • ג'אווה
  • NET.
  • פייטון
  • PHP
  • node.js

בכדי לחבר את השרת שלכם ל new relic יהיה עליכם להטמיע ספרייה קטנה בקוד שתאסוף נתונים מתוך האפליקציה ותשלח אותם לשרתים של NR. NR הוא פתרון SaaS.

על כל שרת שאנו מנטרים בעזרת NR, מתקינים agent. ה agent הזה יודע לאסוף נתונים מתוך מערכת ההפעלה, מתוך הקוד שלנו (שלו הוספנו את הספרייה הקטנה של NR) ועוד סדרה של שרתים – בעזרת מערכת ה Plugins של NR. ישנם Plugins לעשרות אפליקציות מעניינות שנרצה לנטר: שרתי ווב (כמו nginx), בסיסי נתונים, memcached, רדיס, AWS, ועוד

בכדי לצמצם את ההשפעה של ה agent על השרת עצמו, NR מתמקדת באיסוף נתונים בחשיבת עלות (ערך לניתוח ביצועים) / תועלת (ההשפעה על המערכת באיסוף שלהם). כמו כן ה agent מפחית את ההשפעה שלו על השרת בו הוא רץ בכך שהוא אוסף buffer של נתונים ושולח אותם כ batch פעם בדקה (זו החלטה סבירה מכיוון שהניתוח עצמו נעשה כמה דקות אחורה, ולא באמת ב realtime). שליחת Alerts מה Agent, כמובן – מתבצעת בו במקום.

השרתים של NR אוספים את כל הנתונים שה agents שולחים ומבצעים קורולציה (תיאום) ביניהם – לתמונה אחת ואחידה.

חלק מה"קסם" שגרם ל New Relic להיות מאוד פופולארי הוא בהצגת מדדים שימושיים (ולא סתם spam של נתונים) בצורה מאוד נוחה לגישה, ומאוד אינטואטיבית. מרגע שאני מחבר את השרתים שלי ל NR – אני יכול לעבוד מייד, ויש לי סט מסודר והרמוני של כלים ותצוגות לעבוד איתו.

למשל: בצפייה ב Dashboard הראשי, ניתן ללחוץ על כפתור שמציג את הנתונים הנוכחיים, מול נתונים באותה השעה אתמול, ומול נתונים באותה השעה לפני שבוע.

בדומה לחוויית השימוש ב iPhone, גם כאן לא ניתן לקנפג את הפונקציה הזו יותר מדי: אינני יכול לבחור להציג השוואה של "לפני חודש", ושל "ממוצע של שבוע שעבר". אם ארצה, אוכל לפתוח 3 חלונות בדפדפן ולבצע פילטורים בכדי להגיע לתצוגה של המצב הנ"ל. זה יקח זמן ויהיה קצת פחות נוח לשימוש. אבל את ההשוואה של "אתמול" ו"לפני שבוע", שזו השוואה שימושית למדי – אני מקבל בלחיצת כפתור אחת.

זהו Tradeoff בין פשטות ושימושיות, על חשבון יכולת להתאמה אישית.

NR יודע לנטר גם זמן רנדור של אפליקציות ווב בדפדפן ואפילו אפליקציות Native Mobile. יש גם מוצר ל Analytics עמוקים יותר על הנתונים הסטטיסטיים, בשם "Insights". למרות הכל – בפוסט זה אתמקד רק במוצר ה APM לניתוח נתוני ביצועים מהשרת.

על מדד ה Apdex

מדד ה Apdex (קיצור של Application Performance Index), הוא מדד שמזוהה מאוד עם NR, מכיוון שזו עושה בו שימוש אינטנסיבי במוצר.
Apdex לא הומצא ע"י NR, אך בגלל השימוש הנרחב שלו במוצר, כדאי מאוד להבין מה הוא מתאר וכיצד הוא מתנהג.
עצם הרעיון של Apdex נובע מהחסרונות המובנים של מדדים כגון ממוצע או Median. מדדים שכאלו יכולים להסתיר בקלות התנהגויות חריגות ובעייתיות במערכת.

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

כאשר אנו "מסכמים" את ההתנהגות תחת מדדים כמו ממוצע או Variance – אנו מאבדים מידע חשוב.

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

מדוע "Apdex עובד"? – אני לא יודע להסבר. אך הוא נחשב מדד מוצלח.
כמובן שגם הוא לא מושלם.

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

בנוסף ל"בולענים סטטיסטיים", NR עשוי "לעגל פינות" בגרפיים המכילים מידע רב – כך שהתמונה האמיתית תאבד לגמרי. אל תתעצלו: תעשו Zoom In על ציר הזמן (טיפ: בחירת זמן עם העכבר על הגרף) ותפלטרו שוב ושוב את הנתונים לקבלת תמונה יותר ויותר מדוייקת.

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

  • כל טרנזקציה שתסתיים בזמן שהוגדר או מהר יותר – תחשב ל"משביעת רצון" מבחינת הביצועים. (בירוק בתרשים למעלה)
  • כל טרנזקציה שתסתיים בטווח שהוא בין הזמן שהוגדר כ"משביע רצון", עד לפי-4 מכך – תחשב כ "נסבלת" מבחינת ביצועים (בכתום / ירוק זית – בתרשים למעלה).
  • כל טרנזקציה ארוכה מכך, או טרנזקציה שנסתיימה בשגיאה (למשל: HTTP 500) – תחשב ל "מתסכלת".
מדד Apdex הוא אחוז הפעמים בהן הגענו לטרנזקציות "משביעות רצון" ועוד חצי מהפעמים (משקל פחות) בהן הגענו לטרנזקציות "נסבלות". טווחי הערכים של Apdex נעים בין 0.0 (אסון) ל 1.0 (מעולה)הנה דוגמה:

בשרת הזה אנו מצפים לביצוע טרנזקציה תוך 125ms, ומקבלים זאת ברוב הזמן.
מדד של 0.87 הוא טוב – אך לא מעולה. ניתן לשאוף לקצת יותר.

במדידות הדפדפן (NR מסמלצת גם קריאות מדפדפן לשרת – בכדי לבדוק את זמן התגובה של דף באתר, כולל הרינדור) הגדרנו נקודת ייחוס של 12 שניות (פשוט לא הגדרנו נקודת ייחוס) – ולכן אנו נמצאים ב Apdex 1.0 עגול. מעולה! ;-).

במעבר עם העכבר על הגרף אני נחשף למידע נוסף, ויכול לראות שהתנודות ב Apdex שלנו נעו בין 0.84 ל 0.92 בשש שעות האחרונות (נקודת החיתוך) – יציבות סבירה לכל הדעות.

rpm (קיצור של requests per minutes) הוא המקבילה של tps המקובל יותר (transactions per minute) ואנו כרגע עומדים (אני רואה במעבר עם העכבר) על כ 8.43k rpm 130tps, או כ 140tps, עם מגמה קלה של עליה (יש בד"כ מחזוריות ברורה, יומית ושבועית, לשימוש בשירותים)

מדדים עיקריים ש New Relic מספק

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

הנה ה Dashboard העיקרי של NR:

  1. זהו הגרף הראשי המציג "לאן הלך הזמן במערכת". הוא מציג את הממוצע של הזמן שהושקע בבסיס הנתונים, ה Application Server, או קוד האפליקציה שלנו (במקרה הזה – רובי). בגלל ש NR מכיר את ריילס, הוא מסוגל לבצע חיתוך ולהראות לנו כמה זמן הושקע ב ActiveRecords (ספריית ה ORM של Ruby on Rails).
    במבט חטוף ניתן לראות שזהו שירות שמשתמש בתכיפות בבסיס הנתונים (צהוב) – אך יש לו גם הרבה עבודת CPU (תכלת).
  2. זהו הגרף שהצגתי קודם לכן, של Apdex ו Throughput.
  3. זוהי רשימת הטרנזקציות היקרות ביותר (שקלול של זמן ביצוע הטרנזקציה x שכיחות הטרנזקציה). אם נרצה לבצע שיפורי ביצועים בשרת – זה המקום להתחיל בו.
  4. Error rate של השרת – כמות הטרנזקציות שלא הסתיימו כשורה.
  5. רשימת ה alerts שעלו מהמערכת.
  6. רשימת השרתים שב cluster. ניתן לראות CPU, disk-usage, צריכת זכרון ו Apdex – לכל שרת בנפרד.
כשאנו רוצים לשפר ביצועים, הכי הגיוני יהיה להתמקד בטרנזקציות שגוזלות הכי הרבה זמן (משוקלל). ניתן לבחור טרנזקיות ע"פ מדדים שונים (הכי אטיות, גוזלות הכי הרבה זמן, בעלות Apdex הנמוך ביותר, וכו') – ואך לעשות Drill down לטרנזקציה:

  1. אנו יכולים לראות את השונות בזמני התגובה של הטרנזקציות. האם יש הרבה אטיות / מהירות במיוחד – או שיש סוג של זמן קבוע שמסביבו כולן סבות? (צהוב – האחוזון ה 95% האטי, אדום – ה media, ירוק – הממוצע)
  2. לאן הולך הזמן בטרנזקציה: GC, קוד, בסיס נתונים, מערכות 3rd Party וכו'.
  3. כמה טרנזקציות לדוגמה (לרוב מהאזור הפחות טוב). הנה טרנזקציה שלקחה 1.3 שניות.
  4. למרות שמפתה למדוד את הטרנזקציה הגרועה ביותר (#3), לרוב זהו מקרה קצה שעלול להטעות (למשל: בדיוק היה אירוע Full GC).
    אני מעדיף לבחור את השורה השלישית, שהיא קצת יותר נורמטיבית – ולחקור אותה. להזכיר: הזמנים המדוברים הם Wall time clock – וזמן בו הקוד נמצא ב block גם הוא נספר.
והנה כבר ה Trace ש NR אוספת על הטרנזקציה:
לעתים ניתן לזהות מתוך ה trace את הבעיה. בעיות נפוצות הן:

  • "בעיית n+1" – בה יש קשר master-detail בבסיס הנתונים, עושים שאילתה אחת לאובייקט האב ועוד n שאילתות – אחת לכל אובייקט בן (במקום שאילתה אחת עם inner join)
  • שאילתה בודדת יקרה ביותר – ניתן ללחוץ על שורה ולראות את השאילתה הקונקרטית שבוצעה.
  • בעיית קוד (מתאפיינת לעתים קרובות ב GC גבוה).
בתמונה למעלה ניתן לקראות דוגמה שנראית כמו בעיית קוד – 2 פעולות "תשתית" לכאורה, שכל אחת לוקחת יותר מ 300ms. סימן השאלה מסביר ש NR לא עשתה Drill down ומנחה מה לעשות הלאה.

Drill down לתוך הקוד NR בחר במודע לא לעשות – כדי לא להשפיע לרעה על ביצועי האפליקציה. Drill Down שכזה עשוי להיות יקר בצורה מטרידה. במקום זאת, ניתן להוסיף לקוד custom monitors. למשל, הוספת הפקודה הבאה בקוד:

add_method_tracer  :my_method  'Custom/MyClass::my_method'

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

בכדי לא לבצע deploy לכל המערכת, ניתן בקלות יחסית (לפחות ברובי) לכתוב קוד ש"יפתח" ו"יסגור" monitoring על מתודות מסוימות ע"פ קונפיגורציה שנשלחת מרחוק. ניתוחים זריזים שכאלו יכולים להיות בעלי חשיבות רבה מ-2 סיבות:

  1. ייתכן וניסיון לשחזר את הבעיה שלא ב production, עם הגדרות, נתונים, ועומסים ששונים מסביבת production – פשוט לא יצליח.
  2. כלי שמבצע ניטור "שתי וערב" על הקוד – אתם כנראה לא רוצים להביא ל production. הכלי עצמו יכול להכפיל בכמה מונים את כל זמני הריצה של המערכת…

אם אנו רוצים להיעזר ב NR לבצע ניתוח מקיף יותר וממוקד, אנו יכולים להתחיל "X-Ray session" שעוקב אחר דגימה גדולה יחסית של טרנזקציות (נאמר 50 בשעה), למשך זמן מוגבל (נאמר: חצי שעה). על טרנזקציות אלו יאסף כל המידע האפשרי – והמידע ייתן לנו מידע על מגוון טרנזקציות (ולא דווקא האטיות יותר).

עוד יכולות מעניינות (בקיצור)

Developer Mode

ה Developer Mode הוא גרסה רזה של NR שניתן להפעיל On-Premises – על מכונת הפיתוח, ויכולה לשמש לצורך ניטור ראשוני של הקוד לפני שהוא מגיע ל production. למשל, Queries בעייתיים ניתן לאתר בשלב מוקדם כבר כך – ולפני שמגיעים ל production. כמובן שהתנהגות המערכת ב production ועל מחשב של מפתח היא שונה – ולא כדאי לנסות להסיק יותר מדי מתוך ה Developer Mode.

ניתן להפעיל את ה Developer Mode מתוך קובץ הקונפיגורציה, newrelic.yml, ע"י הפיכת הערך developer_mode ל true – ואז יהיה ניתן לגשת ל dashboard דרך http://localhost:3000/newrelic.
ה Dashboard של ה Developer Mode הוא הרבה פחות אטרקטיבי ועשיר – אבל הוא מכיל את נתוני הבסיס החשובים על הטרנזקציות.

דו"חות מוכנים

ל NR יש סדרה של דוחות מגניבים – חלקם אפילו שימושיים! למשל:

  • חישוב ה up-time של המערכת (למשל: 99.9734%) בתקופת זמן נתונה.
  • בניית גרף ה Scalability של המערכת – עלייה בזמני התגובה של השרת ככל שמספר הבקשות גדל (ואולי יש עוד nodes ב cluster בכדי לשרת). גרף זה עוזר לזהות צווארי בקבוק פוטנציאליים.
  • Speed Index – השוואה של הנתונים של השרת שלנו מול אתרים אחרים בתעשייה (לא ראיתי כיצד זה יכול להיות מועיל)
  • מיפוי ויזואלי של התקשורת העיקרית בין השרתים שלכם.
ניתוח אוטומטי של NR על תלות בין כמה שרתים שלנו
Insights
את המידע העצום ש NR אוספת על השרתים שלכם ניתן לתחקר באופן חופשי (יחסית) ובעזרת שפת NRQL (שפה דומה ל SQL) – על מנת לבצע ניתוחים ש NR לא מספקת "Out of the box"

סיכום

שוק ה APM עבר כמה סבבים של שיפורים בשנים האחרונות. New Relic מציג את הזן החדש של המוצרים: קל מאוד להקמה, קל לשימוש והבנה. צבעוני וידידותי למשתמש. כמעט מהנה – כמעט, כי עדיין עדכון של תצוגות הוא עדיין קצת אטי מכדי לאפשר לניתוח "לזרום בקצב החשיבה".

למרות הכיף והנוחות ש New Relic מספק, ניתוח ביצועים של מערכת היא עדיין אחת המטלות שאני מרגיש שבהם אני מנצל את מיטב המשאבים שלי: ללא ידע עמוק על המערכת, ידע תאורטי טוב במערכות הפעלה / רשת / סביבת הריצה הספציפית, וקצת חשיבה מקורית – קשה להגיע בניתוח ביצועים לתוצאות איכותיות.

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

שיהיה בהצלחה!

—–

קישורים מעניינים

הפלטפורמה של NR (מתוך הבלוג הרשמי)
NR ב highscalability.com (פוסט מ 2011)

Crash Course ב NR (וידאו של חצי שעה). מוצלח יותר מרוב החומרים שמצאתי בנושא ברשת
New Relic vs. AppDynamics (פוסט מבית טאקיפי)

על אבולוציה של ארכיטקטורה ו Conway's Law

חברת גטט (Gett, עד לפני שבוע בערך – עוד נקראה גט-טקסי) החברה בה אני עובד, עוברת כרגע שינוי ארגוני משמעותי.

זהו סוג של תהליך שרוב הארגונים עוברים פעם בשנה-שנתיים (אני מניח ששינויים יותר קטנים מתרחשים בערך אחת – לחצי שנה).

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

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

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

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

נתאר את המצב הצפוי הבא, בצוות האחראי על פונקציונליות x:

  • את הקוד שהצוות אחראי עליו (להלן: "מודול A") – יהיה קל ונגיש לשנות.
  • את הקוד שאחראי עליו צוות אחר (להלן "מודול B") – יהיה מורכב יותר לשנות: צריך לתאם, לתקשר יותר, ולהשתלב בעבודה של הצוות השני.

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

חוק קונווי

חוק ידוע בעולם התוכנה הוא Conway's Law שטבע איש מדעי-המחשב מלווין קונווי במאמר משנת 1968. למרות שזמן רב עבר – החוק עדיין נכון ולרלוונטי מתמיד.

החוק אומר כך:

על תכנון של מערכת בארגון נגזר – שהיישום שלה בפועל ישקף את קווי התקשורת בארגון.

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

בואו ואמקד למה אני מתכוון כאשר אני מדבר על "מבנה התוכנה" או "הארכיטקטורה":

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

ההכרה בחוק מותירה לנו 3 ברירות עיקריות:

  1. להלחם במציאות הארגונית – בכדי לגרום למימוש "הנכון" של התכנון, כפי שהוגדר. "לא מעניין אותי שזה בצוות אחר. נכון יותר שזה יקרה כך וכך".
  2. לשנות את המבנה הארגוני, כשיקוף של התכנון שהוגדר – בכדי לאפשר ולתמוך בתכנון שהוגדר.
  3. לשנות את תכנון המערכת, כדי שתשתלב במבנה הארגוני הנתון.
אופציה ראשונה היא סוג של קרב אבוד, סוג של "להיות צודק, אך לא חכם".
אופציה שנייה היא ואלידית ונכונה – כל עוד התכנון המדובר הוא חשוב מספיק בכדי שהארגון יסתדר לפיו. (כלומר: משהו מאוד אסטרטגי לארגון).
אופציה שלישית היא אופציית ברירת המחדל: במקום להלחם בחוקי התכנותיקה ("חוקי הפיסיקה של עולם התוכנה") – לקבל אותם ולהסתגל אליהם.המצב שלנו היום הוא כזה: יש לנו ארכיטקטורה / מבנה של התוכנה שמתנהל יפה – אך מתאים למבנה הארגון הקיים.
שינוי המבנה הארגוני – יוצר פער: וגורם לארכיטקטורה הקיימת לא לתאום יפה למבנה הארגוני. את התיקון נעשה בצורת התאמות של הארכיטקטורה למבנה החדש.

התאמות כגון:

העברת אחריות של מודול m מאחריות של צוות a לאחריות צוות b.
ייתכן והמודול עדיין רלוונטי למשימות והמומחיות של צוות a – אבל צוות b יידרש לעבודה אינטנסיבית באזור הזו, ועדיף שחלק הקוד הזה יהיה מעתה באחריותו. העברת אחריות על פיסת קוד בין צוותים היא לכאורה שינוי ניהולי שאינו קשור לארכיטקטורה, מלבד עובדה אחת: העובדה שהצוות הקודם (צוות a) עדיין צריך חופש מסוים לבצע שינויים ותוספות במודול m.
כיצד מאפשרים לצוות a את היכולת לבצע שינויים בקוד שרוב העבודה עליו נעשית ע"י צוות b – ועבור מטרה אחרת?
האם צוות a יאפיין ויגיש דרישות – בכדי שצוות b יממש אותן בעבורו (סוג של פתרון ניהולי עם תקורה גבוהה)?
אפשרות אחרת היא מעבר הדרגתי ל Plug-In Architecture בו מבנה התוכנה מאפשר לצוות a להמשיך ולפתח חלק מכובד מהפונקציונליות שהוא נדרש לה – ללא תלות בצוות b, וכך לשפר את מרחב-הפעולה העצמאי שלו.
PlugIn Architecture

פיצול של מודול ל-2: חלק שיישאר בצוות a, וחלק שיעבור לצוות b

אנו מתחילים כרגע לבחון את המשמעות של פיצולים שכאלה. לעתים הם לא פשוטים: הם עשויים לגרום לשכתוב של קוד ולפגיעה מסוימת בביצועים (בעיקר בעיות Latency, בגלל שאנו עובדים בארכיטקטורה של מיקרו-שירותים. כלומר: פיצול מיקרו-שירות ל-2 שירותים, ע"פ הצרכים של הצוותים השונים).
בעיה שלישית שיכולה לצוץ היא סיבוך של flow מסוימים: שירות שלישי שצריך כעת לעבוד עם שני שירותים שונים במקום אחד, או פגיעה באטומיות: מה שעד היום התרחש בצורה אטומית בתוך שירות אחד מעכשיו ידרוש coordination בכדי לא לסיים במצב בו רק חצי עבודה נעשתה.
היכן נכון לפצל? מה יהיה ממשק העבודה ביניהם וכיצד הפיצול ישתלב ב Flow? – כולן שאלות טובות.עוד עניין שצץ מחלוקה שכזו הוא עניין של פלורליזם: האפשרות ששני השירותים יכירו תמונות עולם מעט שונות של המציאות, כל אחד ע"פ צרכיו. למשל: אובייקטים המתארים אותו הדבר ("לקוח") יכילו שדות שונים בכל שירות. זה אפשרי כל עוד במידה ויש כפילות – ברור מהו המקור שאליו מתייחסים. כלומר: אם מספר הטלפון של איש הקשר של לקוח מסוים שונה בין שני השירותים – חשוב שיהיה ברור איזה שירות הוגדר כ"קובע העובדה" – והשירות השני יתיישר איתו.
עקרון זה הוא נפוץ ב Microservices, אבל פחות מקובל בארכיטקטורות ריכוזיות.

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

סיכום

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

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

שיהיה בהצלחה!

לינקים רלוונטיים

על השינוי של מייקרוסופט לחברת ענן

AWS: היכרות עם SxS – "השירותים הפשוטים" של אמזון – חלק א'

SxS הוא לא באמת מונח רשמי – "המצאתי" אותו לצורך הפוסט. מה שיש הוא:

  • Simple Notification Service (בקיצור: SNS)
  • Simple Queue Service (בקיצור: SQS)
  • Simple Workflow Service (בקיצור: SWF)
  • Simple Email Service (בקיצור: SES)
כל אחד מהשירותים הללו הוא פשוט למדי וממלא משימה בסיסית אחת, מצד אחד. מצד שני, אלו הן אבני בניין חשובות בבניין מערכות על גבי AWS.

Simple Notification Service

שירות SNS הוא שירות הודעות פשוט, מבוסס סכמה של Publish/Subscriber – כלומר: שליחת הודעת לערוץ מסוים (topic) מצד אחד, ורישום ע"י מנוי אחד או יותר לאותו ה topic – שיקבלו את ההודעות ב push. מנוי HTTP, למשל, יספק את ה endpoint המדויק אליו הוא רוצה לקבל את ההודעה.
מקור: אמזון
דפוס ה Publish/Subscriber בא גם לספק decoupling בין השולח לנמען (הם לא מודעים אחד לשני), וגם לספק שליחה של הודעה פעם אחת, והעברה שלה למספר נמענים, לפעמים בפרוטוקולים או פורמטים שונים של הודעה.
SNS מאפשר לשלוח הודעות בפרוטוקולים שונים, למנויים (Subscribers) שונים. הוא מבוסס push, מה שאומר שהודעות נשלחות למנויים ברגע שההודעה התקבלה (אין polling).
דוגמה נפוצה לשימוש ב SNS היא Monitoring של אירועים אפליקטיביים בשרתים (וריאציה מודרנית: שירותים). כשיש תקלה חמורה אנו יכולים לשלוח הודעה מהשירות שלנו SNS, שהוא מצידו ישלח הודעה לשירות ה monitoring שלנו + מייל + SMS לכונן שזמין באותו הרגע.
מן הסתם ההודעות בפורמט שונה, וכאשר שולחים הודעה ל SNS ניתן להגדיר כיצד תראה עבור מנויים מסוגים שונים.
הרישום של המנויים הוא בלתי תלוי בשירות ששולח את ההודעה, ונעשה ישירות מול SNS. אמזון משתמשת בעצמה ב SNS לתפעול AWS. לדוגמה, ניתן להירשם ב SNS להודעות על auto-scaling, הודעות על איבוד נתונים ב RRS של S3, או אירועים שונים ב RDS (בסיסי נתונים המנוהלים ע"י אמזון).
כלומר: SNS מספק לנו שירותים שליחת הודעות בפרוטוקולים שונים (מייל, SMS, וכו'), בזמינות גבוהה, ובצורה מנותקת מהשירות שלנו. השימוש ב SNS חוסך לנו את ההתעסקות עם הפרוטוקולים ועם ניהול המנויים.
ניתן לשלוח בהודעת ה SNS טקסט שונה לכל פרוטוקול של מנוי
(email-json הוא אימייל שנשלח בפורמט JSON ולא text-based).
SNS יודע לשלוח גם הודעות Push לשירותי מובייל (יכולת שנוספה בשלב מאוחר יותר):
  • Apple Push Notification Service (בקיצור: APNS)
  • Amazon Device Messaging (בקיצור: ADM)
  • Google Cloud Messaging for Android (בקיצור GCM)
  • וכמו כן, לשירותי ההודעות של מייקרוסופט (NPNS ו WNS), ושל Baidu (ענק החיפוש הסיני).
התעריפים של SNS נקבעים ע"פ כמות ההודעות שנשלחו לשירות, וכמות ההודעות שהוא שלח למנויים. התעריפים הם שונים למנויים מסוגים שונים: SMS או מובייל (יקר יותר), אימייל (באמצע), או HTTP/S (זול). הודעות שנשלחות ל SQS הן בחינם.

אמינות ההודעות

מה קורה כאשר נשלחה הודעת SNS ללקוח HTTP שכרגע אינו זמין? אולי השרת בדיוק נפל, או שהייתה תקלת רשת ששיבשה את ההודעה? במובייל ייתכן מצב זמני של ביטול הודעות push / הסרה והתקנה של האפליקציה ("Endpoint is disabled").
עבור חלק מהודעות SNS (למשל SMS, או אימייל), איבוד של הודעה אחת מתוך אלף היא לא בעיה גדולה. במקרים מסוימים – זו דווקא כן בעיה, ואז נרצה לטפל בה.

ל SNS יש מדיניות שליחה מחדש ("Delivery Retry Policies"), המאפשרת להעלות את רף האמינות של ההודעות שנשלחות. לצורך עניין זה אתמקד בהודעות HTTP/S.

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

  • הנמען החזיר קוד HTTP מסדרת 5xx. (כאשר יש 404 או 403, זו לא ממש הצלחה, אבל אין כנראה טעם לנסות לשלוח מחדש את ההודעה).
  • עבר timeout של 15 שניות ללא תגובה מה endpoint.
  • תקלת תקשורת ברורה (תקלה בשליחת ההודעה, SSL certificate לא מתאים, וכו').
אם ההודעה נכשלה ניתן לקבוע מדיניות של ניסיונות חוזרים לשליחת ההודעה.
סה"כ ייתכנו עד כ 100 ניסיונות, ובטווח של לכל היותר שעה.
ל SNS יש מודל של 4 שלבים של Retries, בכל אחד מהם ניתן לקבוע קצב retries ומספר ניסיונות שונה ("קודם תנסה בעדינות, אח"כ דפוק בפטישים!"). הגמישות היא רבה למדי.
את מדיניות השליחה-מחדש ניתן לקבוע ברזולוציה של מנוי.
קישורים מעניינים

Simple Queue Service

שירות המאפשר לנהל Queues (תורים), לשלוח ולקרוא מהם הודעות. זו צורת תקשורת מעט שונה מ SNS:

ההודעה נשלחת ל Queue, והשירות שמקבל את ההודעה שולף אותה ביזמתו מה Queue. לאחר שסיים לטפל בה – מוחק אותה (סדר זה נקבע בכדי לשמור על Data שלא יאבד). למבנה ה Queue יש כמה יתרונות:

  • איזון עומסים בין חלקים שונים של המערכת: כאשר קצב ההודעות מה Producer מגיע ב peaks – ה Queue יאזן אותם. השירות הצורך את ההודעות קובע את קצב העבודה לו הוא מסוגל להגיב – ולכן לא ייפגע מ Self Denial of Service.
  • מבנה ה Queue מאפשר לנתק, במידה מסוימת, בין זמן שליחת ההודעה – לזמן הטיפול בה. למשל: לשלוח הודעות ל Queue במשך כל היום אך להעלות ה Service  שמטפל בהן, רק למשך שעות הלילה – ואז לטפל בכל ההודעות באצווה.

לצורך שיתוף Queue בין כמה צרכנים (בד"כ מספר instances של אותו ה service) – לכל Queue מוגדר Visibility Timeout (ברירת מחדל = 30 שניות). אם הודעה נשלפה, היא נחשבת ל "in flight" ואז יש לשירות שאסף אותה 30 שניות למחוק אותה, או לבקש הארכה. אם לא עשה זאת – ההנחה היא שהוא "נכשל" בטיפול בה (למשל: קרס, איבד אותה, וכו') ולאחר 30 שניות היא תהיה זמינה לאיסוף ע"י instance אחר.

ניתן לבצע חלוקת עבודה בין כמה instances, פשוט ע"י שיתוף של Queue ביניהם:

  • ניתן להאזין ל Alert על עומק ה Queue, ואם נראה שהשירות לא עומד בקצב – לייצר לו עוד instances. אם תרצו – אמזון תנהל התנהגות זו עבורכם בעזרת SQS Based Scaling.
  • בכדי לא לבזבז זמן על Polling, ה API של SQS תומך ב "Long Polling". כלומר: קריאה ש"תתקע" למספר שניות שהוגדר, בהמתנה להודעה שאולי תגיע בזמן הזה – במקום לנסות שוב ושוב לבדוק האם ההודעה הגיעה.
הודעה שנאספה מספר פעמים, אך לא הצליחו לטפל בה – מסומנת כ"הודעה מורעלת" ומועברת ל Dead Letter Queue (אם הוגדרה מדיניות מתאימה).

הנה סיכום של כמה מההבדלים בין SQS ו SNS:

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

עבור השגה של ה Scalability, אמזון מציע Soft-FIFO בלבד. כלומר: הודעות יהיו "בערך" First In-First Out, הסבירות שהודעה a תשלף מה Queue לפני הודעה b גדלה ככל שהודעה a נשלחה זמן גדול יותר לפני הודעה b. ערבוב בין הודעות שנשלחו בזמן קרוב מאוד – הוא יחסית צפוי. ערבוב בין פרקי זמן ארוכים יותר (מספר שניות) – הולך והופך נדיר.

גודל ההודעה האפשרי הוא של 256KB.

ההגדרות של Queue, ב SQS

SQS הוא לא שירות יקר, אבל ניתן לחסוך עוד בעלויות ע"י שליחה של אצוות של עד עשר הודעות, במחיר של שליחת הודעה אחת – כל עוד הגודל הכולל של ההודעות באצווה לא גדול ממחסום ה 64KB.
אמזון מספקת ספרייה בשם AmazonSQSBufferedAsync client שמסייעת לנהל את האצוות, כמעט לבד, עבורכם. כרגע היא זמינה (ככל הידוע לי) רק בSDK לג'אווה.

אמזון מציעה מיליון בקשות ל SQS בחודש (לחשבון, בעת כתיבת פוסט זה), קריאה, כתיבה או מחיקה – בחינם. המחיר של כל מליון בקשות נוספות ל SQS הוא כחצי דולר.
אמנם גודל ההודעה המרבי הוא 256KB, אולם אמזון מחשיבה בקשות הגדולות מ 64KB, לצורכי תמחור, כבקשות נוספות. למשל: קבלת הודעה בגודל של 150KB – תחשב בתמחור כ 3 בקשות, למרות שנעשתה קריאת HTTP יחידה.

SQS vs. Kinesis
אמזון הציגה לאחרונה שירות נוסף בשם קינסיס (פירוש השם: "תנועה") – שגם הוא מספק ניהול Queues, אמין, זמין, היכול לתמוך ב Scale גבוה. קינסיס הוא "חיקוי" של Apache Kafka, עם כמה שינויים קלים.

מצד אחד – באמזון טוענים ש "SQS יכול לעמוד בכל Scale".
מצד שני – בעוד SQS הוא מנוהל לחלוטין יש לו כמה "כאבי ראש" שיש להתמודד איתם:

  • עליכם לנהל את ה shards אליהם מחולק ה Queue – בכדי להגיע Scale. כל shard מוגבל לטיפול של אלף הודעות בשנייה.
  • קינסיס הוא "פחות realtime-י": הוא לא יאפשר לתשאל על הודעות חדשות (לכל shard) יותר מ5 פעמים בשנייה (כן, הוא סופר).
  • הנתונים נשמרים על קינסיס כ 24 שעות (מול 14 ימים של SQS).
  • גודל הודעה בקינסיס מוגבל ל 50KB (מול 256KB של SQS),

למה, אם כן, להשתמש בקינסיס ולא SQS?!

על הבדל מהותי אחד, ניתן ללמוד מתוך התמחור של קינסיס:

  • כ 2 סנט לכל שעה בו השירות פעיל, ולכל ~7GB של הודעות שנשלח. כלומר: ~10GB כל שעה, לאורך 24 שעות = 24*2*2 = בערך 1$.
  • כ 3 סנט לכל מיליון פעולות כתיבה ל Queue. כלומר: ~10GB כל שעה, לאורך 24 שעות = בין 15 סנט ל ~7 דולר, תלוי בגודל ההודעות.
  • שימוש ב SQS לתעבורה דומה יעלה בין 10$ ל 360$ (חישוב אצבע, תלוי בגודל ההודעות, שימוש באצוות, וכו').
הבדל נוסף הוא שבקינסיס לא מוחקים הודעה שהתקבלה. אם משהו השתבש בשלב מאוחר יותר ב flow טיפול ההודעות, ניתן "להחזיר את המצביע" כמה שעות לאחור ולהתחיל את התהליך מחדש. כמובן שיש לתכנן את המשך ה flow באופן שיוכל להתמודד עם מאסה של הודעות שנשלחו שוב.
בקיצור: קינסיס (כמו קפקא) היא תשתית שנכתבה להעביר אצוות גדולות מאוד של הודעות – בצורה יעילה, בד"כ: נתונים ב flow של Data processing. אם אתם שולחים GBs של נתונים, מסביב לשעון, כנראה שגם SQS יוכל לספק את השירות – אבל קינסיס עשויה להיות זולה משמעותית ולהתאים יותר לתהליך.

סיכום

בחנו שני שירותים פשוטים, אך חשובים מאוד של AWS: שירות ההודעות, ושירות ניהול התורים.
בפוסט הבא נבחן את שני השירותים האחרים: שירות הדואר האלקטרוני, ושירות ה workflows.

שיהיה בהצלחה!

על העוצמה הטמונה ב"טכנולוגיות משעממות" [דעה]

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

חשבו על התרבות שלנו (קולנוע, ספרים, חדשות, וכו'): האם יש בה מקום גם למתמחים או רק למומחים? המתמחים יהיו מומחי-על בעוד 30 דקות של סרט הוליוודי, או שהם דמויות משנה שעיקר תפקידן הוא להאדיר את ההילה מסביב למומחה – שהוא עיקר הסיפור.

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

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

בעיה של חלוקת-קשב

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

למהנדס שחי 30 שנה לפנינו, היו הרבה פחות גורמים-מושכי-תשומת-לב: לא היה What'sApp שמצפצף כל עשר דקות, טוויטר בו עשרות רעיונות חדשים צצים כל יום, והספרות המקצועית הייתה יושבת בספריות האוניברסיטה או שהיו מזמינים אותה דרך קטלוג – והיא הייתה מגיעה אחרי חודש-חודשיים.

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

הקשב שלנו הוא משאב מוגבל. אנו יכולים יכולים להתמקד בנושא אחד לעומק, או בשלשה נושאים במקביל, ולהתעמק רק רבע(~) מכך. למה רבע? כי יש לנו Context Switch יקר [א].

אני חושש, שעבור מהנדסים צעירים בימים אלו, המקבילה של מה שקורס ה"נושאים מתקדמים במערכות היפר-מבוזרות, מתייצבות עצמית, מונחות בינה מלאכותית" היה עבורי – היא בד"כ טכנולוגיות חדשות: Docker, AngularJS, React, Scala, או בקיצור: Just Name It!

הדרך להתבלט, ולהרגיש מומחה, עוברת בשימוש בטכנולוגיה ה"מגניבה הנוכחית": "אני כותב ב Rust", "Go", או "Swift" – הוא סמל סטטוס, נחשק לא פחות מהעבודה היומיומית בשפות עצמן.

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

לאחר שעברתי כמה וכמה פעמים בחיי ל"טכנולוגיות מגניבות" (כן, ניסיתי את AngularJS, Docker ו React – ועוד מגוון טכנולוגיות שהיו "מגניבות" בזמנן…), אני מוכן להצהיר: בכל הטכנולוגיות החדשות הללו יש גם אזורים לא נעימים, במיוחד כשהן ממש חדשות.

רוב הפעמים, רוב מי שמאמץ את הטכנולוגיות לא זוכה לשיפור ביכולת שלו לספק deliveries מהירים יותר או טובים יותר – אלא בעיקר ביכולת שלו להרשים אחרים  ("תשואות, ללא תשואה").

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

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

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

איזון הוא לב העניין

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

מבחינה מסוימת, החתירה של מתכנת או צוות בודד בארגון לאמץ טכנולוגיה חדשה משיקולים אישיים הוא Local Optimization שאולי נחמד להם – אך נוגד את האינטרסים של כלל הארגון (ה Global Optimization).

מצד אחד, צמחה בשנים האחרונות גישת ה Ployglot Programming: "אל תפחדו לפתח במספר שפות תכנות – זה בסדר גמור". כך ניתן "להתאים את שפת התכנות לבעיה הנכונה".

מצד שני, לריבוי שפות-תכנות (או ספריות) שבשימוש יש גם בעיות:

  • קוד נוטה לא-להעלם: אם שוכחים ממנו – הוא לא באמת נעלם, הוא רק הופך לקוד Legacy בו צריך לבצע תיקונים מדי פעם. בכדי לבצע תיקונים – יש להכיר את שפת התכנות / הספריות שבשימוש ברמה סבירה כלשהי. "טריפ" של החלפת טכנולוגיות תדירה תשאיר אותנו עם גן-חיות של Legacies שיש לתחזק. זה הזמן לעבור מקום עבודה…
  • אף אחד מאיתנו הוא לא ליאונרדו דה-וינצ'י (איש אשכולות [ב]) – כלומר: לא ניתן להגיע לרמת מומחיות גבוהה במספר טכנולוגיות בו זמנית. זה או להגיע לשליטה X ב-3 טכנולוגיות, או X/2 ב-5 או 6 טכנולוגיות. יש כאן trade-off ברור.
  • חיבור בין טכנולוגיות שונות מציב, פעמים רבות, תקורה.

באימוץ של טכנולוגיה עדיפה יש תקופה (נאמר שנה-שנתיים) עד שהשימוש בטכנולוגיה החדשה נעשה באמת יעיל: עקומת למידה של כלל ה R&D, ניסיון שנצבר, ובעיות חדשות שצצות איתה – ונמצאים להן פתרונות יעילים. אם מחליפים טכנולוגיה כל שנה-שנתיים – ייתכן ולעולם לא מגיעים לשלב החשוב הזה.

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

תובנה מעניינת ששמעתי בכנס GOTO; Berlin הגיעה מניתוח השימוש בחנויות ספרים מקוונות: לא רק בעולם הטכנולוגיה יש נטייה ללכת אחרי "החדש". הם הראו שגם רוב ספרי הניהול שנמכרים (ניהול – דיסיפלינה שמשתנה לאט) הם מהשנה האחרונה, או השנה שלפניה.

שנייה! האם גם הרופא שלי עשוי לנסות "את הטכניקה החדשה ביותר" כי ככה הוא ירגיש "מגניב יותר"? פעם עברתי טיפול שהרגיש לי ממש כך…

לוח פתקיות. לא "מגניב" כמו Mingle או ScrumWise – אבל עובד מצויין, וללא Learning Curve.

אבל…

תרגיל שכנוע נחמד הוא לנופף באופן שבה טכנולוגיה חדשה עושה משימה ספציפית בקלות רבה.
כמה משעשע יהיה מצדי להראות כיצד שפת התכנות החדשה שהמצאתי, FibLang, מייצרת בקלות רבה יותר מכל שפה אחרת בעולם סדרה של מספרי פיבונאצ'י. הנה הקוד שנדרש:
do!
המ..המ, האם יש לכם שפת תכנות טובה יותר מהשפה הזו? בואו נזרוק את פייטון ונעבור כולנו ל FibLang FTW!!!

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

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

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

כנ"ל לגבי Frameworks, בסיסי-נתונים, וכו'.

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

מה עושים?

ניתן לעשות חישוב עלות/תמורה פשוט בכדי לבחון האם אימוץ טכנולוגיה משתלם – וכך לאמץ טכנולוגיות במינון האופטימלי.

הבעיה נעוצה בכך שהבעיה היא לא בעיה חישובית פשוטה, אלא יותר בעיה פסיכולוגית / חברתית. כאשר ממש רוצים לאמץ טכנולוגיה יש טיעונים גנריים שנשמעים משכנעים. למשל:

  • "המעבר אולי ייקח שנה-שנתיים – אבל אז נהנה מכל היתרונות שלה למשך כל השנים שלפנינו!" (ולא נחליף טכנולוגיה שוב כעבור שנים בודדות?)
  • "אבל משתמשת בטכנולוגיה הזו – ותראו לאן הם הגיעו!!" (אולי נדבר כל היום רק אנגלית במשרד, כי בחברה ההיא עושים זאת – ותראו לאן הם הגיעו !!)
  • "מתכנתים פשוט לא ירצו לבוא לעבוד פה, בידיעה שאנו עובדים עוד בג'אווה גרסה 1.6 בלבד…" (אבל חידוש טכנולוגיות הוא התרגשות זמנית למפתח – שמתרגלים אליה מהר מאוד. בסוף היתרונות / חסרונות העקרוניים של הארגון הם שיקבעו).

אם הבעיה היא פסיכולוגית / חברתית, אולי ראוי שגם הפתרון יהיה פסיכולוגי / חברתי?

באוניברסיטה אחת ראיתי ששינו את שם קורס ה"מבני נתונים" ל"נושאים מתקדמים באלגוריתמים". ניסיון נחמד.

במשך תקופה השתעשעתי ברעיון שאולי, רק אולי, גוגל מאפשרת למהנדסים לעבוד על "מה שהם רוצים" כ20% מהזמן בכדי שישחררו שם אנרגיות – ושאר הזמן יתמקדו בעבודה? מסתבר שגם ה 20% הם לא ממש…

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

אפילו אם ההבנה שטכניקות הנדסת-תוכנה הן חשובות יותר, קשה למלא בעזרתן את הצורך בהפגנת מומחיות / ייחוד.
הייתה תקופה בה Design Patterns היו "הדבר החם", סוג של טכניקה ולא טכנולוגיה – ואז עשו בהם Overuse מוגזם שגרם לנזקים רבים.

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

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

אין לי פתרון. אני לא יודע מה אפשר לעשות.
אני החלטתי לכתוב פוסט בנושא – אולי הוא יעזור במשהו 🙂

—-

[א] מונח מעולם מערכות ההפעלה. כאשר נראה לנו שכמה יישומים רצים על אותו CPU core במקביל, הם בעצם רצים עליו סדרתית, כאשר מערכת ההפעלה מחליפה ביניהם כמה פעמים בשנייה ויוצרת את אשליית המקביליות.
ההחלפה הזו, דורשת כמה פעולות ממערכת ההפעלה ומייתרת חלק מזיכרון המטמון (בעיקר במעבד ובזיכרון) – מה שגורם לכל החלפה לגזול זמן לא מבוטל = תקורה.

באופן דומה, בני אדם שעוברים בין נושא לנושא יהיו פחות מרוכזים בנושא אליו עברו במשך כמה דקות. נוטים לייחס למוח האנושי context switch של 15 דקות, כלומר: כאשר אנו מחליפים נושא לוקח לנו כרבע שעה להגיע לאותה רמת ריכוז ויעילות שבה היינו בנושא הקודם שבו עסקנו. בממוצע גס – ניתן לומר ש 7 וחצי דקות מזמננו (ממוצע גס בין 0 ל 100% ריכוז) מתבזבזות בכל החלפת נושא. אם אנו עושים 20 דילוגים ביום בין נושאים, הלוך ושוב, בזבזנו שעתיים וחצי של פעילות המוח שלנו ביום הזה.

[ב] שנחשב כמוביל עולמי בד-בבד במספר תחומים, בתקופה בה הוא חי.