שיקולים בתכנון מקביליות: Beyond Threads

מקביליות (concurrency) מתורגמת ע\"י לא מעט אנשים ל Thread ו synchronized (בג\'אווה) – דבר שהוא נכון, אבל מסתיר כמה אלטרנטיבות חשובות.

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

Thread נתפס כ\"אמצעי להאצת התוכנה\", אבל זה לא בדיוק נכון. אם יש לי משימה מקבילית שכוללת הרבה I/O (כגון client להורדת קבצים מהאינטרנט) הגדרת thread לכל קובץ או segment שמורד היא הדרך הקלה לפיתוח, אבל לא הדרך היעילה.

דרך יעילה יותר היא הגדרת thread יחיד שעובד עם ערוצים רבים של IO אסינכרוני (כגון channels בספרית java.nio. מקביל לפקודת select ב C של unix/linux, למי שמכיר). בגישה זו יש thread יחיד שמאזין לרשימת ערוצי ה IO הרלוונטים (sockets מאתר ההורדות + streams לכתיבה לקבצים) וכל פעם שערוץ IO זמין לקבל פקודה (התקבל packet ברשת או נסתיימה כתיבה של באפר לדיסק)ה thread שלנו יתעורר ע\"י event. עליו לעשות איטרציה ולבדוק איזה ערוצ(י)  מוכנים, לבצע את הפעולה ולחזור לישון עד פעולת ה I/O הבאה שהסתיימה.

אז מה חסכנו בעבודה עם thread יחיד (בסדר עולה):

  • יצירה של thread היא פעולה יקרה (thread pool עוזר להתמודד)
  • תזמון ה threads השונים הוא overhead.
  • לcontext switch בין threads יש מחיר.

כתיבה ב Thread אחד היא בהחלט יותר יעילה! בכל זאת ברוב הפרוייקטים הייתי מעדיף לעבוד עם מספר threads. דוגמת אפליקציית ההורדות היא דוגמא פשוטה במיוחד שבה כל ה threads הם אחידים, אבל לרוב המצב יותר מורכב. כמות הרווח מ thread יחיד תתרום, נאמר, 5% לביצועי המערכת? לא שווה ברוב המקרים לייצר קוד מסובך בשביל שיפור שכזה.
סיכום: thread יחיד היא אופטימיזציה טובה למקרים כמו המתואר לעיל.

היבט חשוב נוסף הוא מערכת multi-core שאותה ניתן לנצל רק עם מספר threads שיתאים למספר ה cores.
אם הייתי מריץ את המערכת הנ\"ל על מערכת עם ארבעה cores (וייתכן היה שיש לי מספיק ערוצי IO להעסיק את ה thread עד תום) – הייתי רוצה 4 threads שינצלו את ה CPU עד הסוף. דוגמא קלאסית היא WinZip שעובד עם thread בודד מול תוכנות דומות (winrar, 7zip) שעובדות עם מספר threads:

אפרופו multi-core: הנוסחא המקובלת לבחור כמה threads לייצר ליעילות מרבית היא:

# threads = # of cores / (1 – blocking coefficient)
כאשר המקדם (Blocking Coefficient) הוא ערך מ 0 עד 1 כמה אחוז מהזמן ה thread ישן בין פעולות IO. אם יש לי מערכת עם 4 cores שישנים 30% מהזמן, אני ארצה לעבוד עם 6 threads.
Runtime.getRuntime().availableProcessors();
ייתן לי בג\'אווה את מספר הcores הלוגים (יתחשב ב hyperthreading).

אסטרטגיות מקביליות

אחד הדברים שכן כואבים במספר threads הוא עלות הסינכרון. אם לא נסנכרן – יכולים להיות שיבוש מידע, deadlocks ו livelocks. אם אנחנו מסנכרנים, אז המחיר הוא בביצועים: כל lock שמגיעים אליו n threads גורם לכך ש n-1 יאלצו \"לישון\" למרות שהם רוצים לעבוד. דמיינו בעבודה את קבצי ה excel שמישהו פותח ואף אחד לא יכול לעבוד עליהם (כי הם נעולים), אבל במקום לעבור למשימה אחרת – כל מי שניסה לפתוח את הקובץ חייב ללכת לישון! (ועד עובדי חברת החשמל – רעיון לעיונכם). יצירת המון threads במקום לרוב לא תשפר את המצב: תשלמו הרבה על context switch בלי לפתור את הבעיה המהותית.

יתרה מכך, סינכרון חוסם את מידת ה scalability האפשרי בריבוי cores.
בהינתן מערכת ש 5% מזמן הביצוע שלה הוא קטע מסונכרן, אפילו אם יהיה לי את ה banana bridge i9-9990EX של אינטל שיצא ב 2024 עם 6400 cores, לא אוכל להשיג יותר מפי 5 ביצועים מאשר על מעבד ה i5 ארבעה cores הסטנדרטי שלי (בהנחה שלא היה חיזוק כוחו של כל core ושזו משימה יחידה שאני מריץ). נשמע דיי מאכזב למי שמתכוון לחכות לbanana bridge מעכשיו.

עקרון זה ידוע כ Amdahl\'s Law וניתן לקרוא עוד עליו כאן. הפיתרון הוא לצמצם את כמות הסינכרון למינימום.

אז איך מפחיתים את כמות הסינכרון למינימום? ישנן מספר אסטרטגיות להתמודדות עם סנכרון:

  • mutable synchronization
  • isolated mutability
  • pure immutability
  • actors

mutable synchronization
זו הגישה שרובנו בוחרים בד\"כ באופן אוטומטי בלי לשים לב. העקרון הוא לשים synchronized על כל מתודה שיש בה שינוי state שיכול להשתנות בין threads. זו הגישה הקלה והפחות יעילה. דרך שיפור מהירה היא לכתוב את ה synchronized בבלוקים הכי קטנים שאפשר ולא בחתימת המתודה (למי שלא מכיר – תנסו – אפשר לכתוב אותם אפילו על שורה בודדת).

isolated mutability
גישה זו היא צעד אחד הלאה, לצמצם את כמות הסינכרון למינימום – שזה המשתנים עצמם. במקום לעבוד עם Long אני אעבוד עם AtomicLong של java.util.concurrent שמספק לי פעולות אטומיות כגון getAndIncrement או incrementAndGet
שימוש בהן יאפשר לי לצמצם את הסינכרון לנתונים עצמם ולא מעבר.

pure immutability
זו גישה הפוכה לגמרי שאומרת – אל תשנה משתנים. כל ערך שתיצור יהיה immutable (כמו String), כל פעם שתצטרך ערך אחר – צור אובייקט חדש. גישה זו דיי קשה ולא כ\"כ נתמכת בג\'אווה. אם פיספסתי – הקומפיילר לא יתריע וגם יש כמה מצבים בעייתים שאצטרך להתחכם בהם. Closure דוגמא לשפה שתומכת בגישה זו באופן מובנה.

actors
זו גישה שפופולארית היום ב scala (השפה שנוצרה ל multi-core ו scalability). הגישה מדברת על active objects או actors שהם אובייקטים \"חיים\" – כלומר ה threads. לכל actor יש תור נכנס (\"דואר נכנס\") והם מתקשרים אחד עם השני רק בהודעות אסינכרוניות (שמונעות מצב של deadlock). בזכות התקשורת – אין צורך בסנכרון בכלל. גישה זו ניראית מוצלחת וישימה, לא ניסיתי בעצמי – אך שמעתי כמה סיפורי הצלחה ממקור ראשון. נראה שהיא גם עובדת יפה כשהמערכת גדלה והופכת למסובכת.
אמנם בג\'אווה אין תמיכה בשפה ל actors אך יש מספר ספריות (כגון akka או GPars) שלמרות שנכתבו בשפות שונות על ה JVM – עובדות יפה מתוך Java. הגישה מתאימה, אגב, גם לסנכרון בתוך אותו JVM וגם ב remoting בין JVMs שונים (כגון nodes שונים ב cluster).

—–

קישורים
מעבדי XEON מול Power8 של יבמ: http://anandtech.com/show/9193/the-xeon-e78800-v3-review

ארבעה דברים טובים שנוספו עם Java 7

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

סיכמתי כמה דברים חיוביים לאלו שיעברו ל Java 7, במקרה או בכוונה, ששווה להכיר:
פחות צורך במשמעת עצמית ב Exception Handling
Java נבנתה בצורה שתקל על המפתח להמנע משגיאות, הפחזבל (Garbage Collector) חסך מיליוני שנות פרך של debug וחיפוש אחר זליגות זכרון. בכל זאת, חברה שלא אנקוב בשמה, שילמה 17 מיליון דולר השתתפות בנזקים של הלקוח בעקבות הבאג הבא (חפשו אותו):

  Connection conn = null;
  Statement stmt = null;
  try {
    conn = connectionPool.getConnection();
    stmt = conn.createStatement();
    // Do the lookup logic
    // return a list of results
    } finally {
      if (stmt != null) {
        stmt.close();
      }
      if (conn != null) {
        conn.close();
    }
  }

אני מניח שהבאג לא צועק, הקוד נראה במבט ראשון מסודר ונכון. אבל מה – אם ()stmt.close יזרוק exception (בגלל מנגנון ה keep alive  של Oracle?), ה connection לא יתנקה וכשפעולה זו תחזור שוב ושוב, Oracle יסרב לקבל עוד קריאות. במערכת Mission Critical המשמעות היא לבצע restart לבסיס הנתונים כל מספר דקות, חוסר יכולת לעבוד, יום בטלה לעובדים והפסד אדיר ללקוח.

הפתרון הוא לעטוף ב try-catch נוספים (ה catch יישאר כנראה ריק) את קריאות ה ()close של stmt ו conn. זה היה ה best practice שדרשנו ממפתחים לעשות, שוב ושוב, וברגשות מעורבים.

איך מוודאים שבקשה זו תיושם בפועל? ביצוע תחוף של Code Reviews, הגדרת המודעות בקרב המפתחים ובארגון שעובד נכון – בניית Connection Pool שיודע לזרוק Connections בשעת לחץ.
בג\'אווה 7 ניתן לכתוב את הקוד הבא:

  try (Connection conn = connectionPool.getConnection();
       Statement stmt = conn.createStatement()) {
    // Do the lookup logic
    // return a list of results
    } catch {
      // respond to exception

    }

  }


שדואג ש conn ו stmt ייסגרו, אם לא שווים ל null ולמרות exceptions שיכולים להזרק. הוא מקביל לקוד הארוך והמכוער שתארתי למעלה. נחמד!

פחות חזרה חזרה חזרה ב catch statement
תופסים שלושה סוגי Exception ורוצים לעשות אותו הדבר?
מעכשיו כתבו:

} catch (IOException | SQLException | SQLStatementException ex) {
  log.warn(ex);
  throw ex;
}
המשתנה ex יתייחס לסוג ה Exception (מתוך השלושה) שנזרק. יופי.

Performance Profiling: שחרור VistualVM
אם תחפשו בתוך ספריית Bin ב JDK שהורדתם, תגלו שיושב לו שם Profiler בשם VisualVM. מלבד כך שהוא חינמי, מתחבר לכל ה IDEs החשובים (עם plugin) ויש לו ממשק משתמש נחמד, הוא מספק נקודת איזון מאוד מוצלחת של פשוטות מול עוצמה. הוא ידידותי – אבל גם אינו צעצוע. הוא יכול להספיק לרוב משימות ה profiling הנפוצות, גם בתוך tomcat, ואינו דורש הגדרות מיוחדות לJVM או לשרת שאתם עובדים איתו.

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

נ.ב. – אופס, תפסתם אותי. VisualVM מסופק החל ממרץ כבר ב JDK 1.6 ואינו חידוש של Java 7. בכלל הוא יכול לעבוד (תחת מגבלות) עם אפילקציות שקומפלו ב JDK1.4. הוספתי אותו לכאן מכיוון שהוא תוספת מכובדת ל JDK שקל לפספס בגלל שיצא ב update ולא ב major release.

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

בהצלחה!

מה Amazon עושים נכון?

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

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

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

אני אקצר לכם, אבל הוא מדבר על SOA ואיך ארכיטקטורה שמחייבת אנשים לעבוד בממשקים מוגדרים היטב, ללא קיצורי דרך (זכרון משותף, למשל) גורמת לאנשים לצמצם תקשורת לאותם ממשקים. ואז – דברים מתפרקים: למשל מתרחשים (SDoS (Self Denial of Service כאשר שירות מהיר קורא לשירות איטי הרבה פעמים. לא היו מפתחים שמדברים אחד עם השני ויכלו למנוע זאת. 

וכך… כך מתפתח ה DNA* הארגוני: כל Service נבנה בצורה robust ו isolated לחלוטין. \"על המפתח להגן על הקוד בפני… עצמו\", אמר כבר פרדריך ברוקס בשנות השבעים.

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

שווה לקרוא בשפת מקור (context: נכתב ע\"י אדם שעובד כשש וחצי שנים בגוגל):

Google+ is a knee-jerk reaction, a study in short-term thinking, predicated on the incorrect notion that Facebook is successful because they built a great product. But that\'s not why they are successful. Facebook is successful because they built an entire constellation of products by allowing other people to do the work. So Facebook is different for everyone. Some people spend all their time on Mafia Wars. Some spend all their time on Farmville. There are hundreds or maybe thousands of different high-quality time sinks available, so there\'s something there for everyone.

Our Google+ team took a look at the aftermarket and said: \"Gosh, it looks like we need some games. Let\'s go contract someone to, um, write some games for us.\" Do you begin to see how incredibly wrong that thinking is now? The problem is that we are trying to predict what people want and deliver it for them.

You can\'t do that. Not really. Not reliably. There have been precious few people in the world, over the entire history of computing, who have been able to do it reliably. Steve Jobs was one of them. We don\'t have a Steve Jobs here. I\'m sorry, but we don\'t.


שזה גם סוג של הספד נוסף לסטיב ג\'ובס. האיש שידע להמר בענק ולקלוע (…נושא גדול ומעניין שאשמח לחזור ולעסוק בו).


בקיצור, יפה.


אפשר למצוא את המקור כאן:

הרגישו חופשי להוסיף תובנות עקרונויות נוספות שפספסתי / לא ציינתי.

כמובן שדברים יכלו להתפתח אחרת.

Performance: דחיינות = מקצוענות?

הפוסט עודכן ב 16/10



שאלה: כיצד כותבים קוד שבנוי לביצועים גבוהים?
תשובה: בדיוק אותו הדבר.


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


הקדמה
פעם, עבדתי עם מתכנתת שקיבלה הערות על מסמך Design שכתבה ונראתה פגועה: \"כתבו לי שה-Design שלי ילדותי\". מה?? שאלתי – תראי לי. קראתי את ההערה והיא הייתה: \"premature optimization\".

Premature Optimization
\"Premature Optimization\" למי שלא הבין אינה קשורה לילדותיות, אלא לאופטימיזציה שלא הגיעה זמנה. הזקנים שביננו שלמדו פיתוח בשפת C יכולים עוד לזכור את הסנסיי (במקרה זה מרצה מזדקן למדעי המחשב שעסק במקור במתמטיקה) סופר לנו כל ביט וכל פעולת if. \"מה?, כתבת x/4? ברור ש x*0.25 זה מהיר יותר. בכלל הייתי מצפה ל x>>2\" – הם הכו בנו תורה (סלחו לי אם השיפט הוא לכיוון ההפוך, מרגיז אותי בכלל לבדוק).
בשנות השבעים, שהמחשב ביצע מאות פעולות בשנייה – הייתה לאופטימיזציה כזו חשיבות. טראומת הקוד-הלא-אופטימלי היה כ\"כ קשה שעד היום יש זכר לצלקות (במיוחד באקדמיה).

כיום, מחשב ביתי ממוצע מכיל 2 או 4 ליבות, בקצב של לפחות 2 מיליארד פעולות בשנייה (Ghz), עם instruction-set (כגון MMX או SSE – אליהם ניתן לגשת בעזרת ספריות מיוחדות בשפת C) שמבצעים פעולות ארוכות ומסובכות בצורה יעילה יותר. רק אזכיר שהיום לכל מחשב חדש יש גם (GPU – Graphical Processing Unit) אותו כרטיס גרפי שמובנה בלוח האם, בתוך ה CPU או על לוח נפרד. יחידות עיבוד אלה בנויות לביצוע פעולות מתמטיות פשוטות במקביליות גבוהה ויכולים להציג כח חישוב מפחיד.


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

למה לעשות אופיטמיזציה?
אז מה ניתן להסיק? שחשיבה על יעילות היא לא חשובה? כן – ולא.
כוח העיבוד הפך זול, הזכרונות יכולים לשמש כתחליף לנייר טואלט, אבל זמן המתכנת הוא יקר. כל אלה מובילים עוד ועוד אנשים למסקנה שיש לדחות אופטימיזציות performanceכמה שרק אפשר, וחלקן הגדול אין בכלל לעשות. חשוב לציין 2 סייגים חשובים מאוד:
  • אלגוריתמים (או מבני נתונים שעליהם מבוססים האלגוריתמים) עלולים להיות חסיני-כח-מחשוב. חיפוש ב O(N) מול O(logN), כאשר רשימת האלמנטים עולה על כמה אלפי איברים, יעשה את ההבדל בין תגובה מהירה להפסקת קפה (של המשתמש, כמובן). כאן אין על מה להתפשר.
  • לחזור לפונקציה אחרי שנה ולשפר כל אלמנט למקסימום – זה קל (במיוחד אם יש unit tests). לשפר ארכיטקטורה – זה קשה מאוד. על הארכיטרטורה להיות יעילה מבחינת ביצועים מההתחלה.
אתם עשויים להשאר ספקנים, אז אציג דוגמא אחת של שיפור ביצועים שחוויתי על בשרי: דפדפנים.
תחום הדפדפנים החל ברצינות באמצע שנות התשעים – כלומר, ידע רב הצטבר בתחום בחמש עשר השנים האחרונות. 
אני זוכר מקרה שבו אפליקציית web שכתבנו הייתה איטית להחריד. לדף מלא לקח 56 שניות (!) לעלות על reference client hardware, שהיתה מכונה חלשה מהרגיל כדי לייצג את המשתמש עם המחשב שמיושן. המעבר מ explorer 6 ל explorer 7(שאז היה חדש) שיפר את טעינת הדף לפחות מ 12 שניות. מקור הבעיה היה קובץ javascript גדול במיוחד. ניתוח מקיף הראה שאספלורר 6 ביזבז יותר מ 40 שניות על פיענוח (parsing) של הקובץ בעוד מנוע פיענוח חדש באספלורר 7 הוריד את הזמן לשניות בודדות (הנה דוגמא לסדרי גודל).
\"כיצד יכול להיות שיפור כ\"כ גדול בגירסה מס\' 7 של מוצר?\" תהיתי זמן רב. האם הדפדפנים הגיעו לקצה גבול היכולת? עם כל אופטימזציה אפשרית? (צחוק גדול ברקע)

הנה התבוננו במספרים מתוך מבחני ביצועים של האתר הראוי Tomshardware. המבחן בחן דפדפנים שונים על חומרה זהה שבבסיסה מעבד i7-750.


מרכיב משמעותי בימנו הוא הרצה של קוד JavaScript. בשנים האחרונות היו שיפורים משמעותיים בכל הדפדפנים, האם אפשר להשיג יותר?
הנה פיירפוקס 3.6 וכרום 10 ו אקספלורר 9 (מרס 2011) מול פיירפוקס 7, כרום 14 ואקספלורר 9 עם מספר עדכונים (ספטמבר 2011). מוצרים לא לגמרי חדשים, שנוצרו ע\"י טובי המהנדסים:
הרצת JavaScript במבחן Kraken 1.1

מהההה???

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


הנה עוד מבט, כמה אפשר עוד לשפר ממוצר קיים ובוגר את זמן העלייה (startup time)?


בחצי השנה הזו Chrome הצליח להוריד את זמן העליה מ6 ל2 שניות – שליש מהזמן המקורי (תוך כדי שיפורים בזמן טעינת הדף) וגם Opera הותיק הציג שיפור חסר תקדים. שאר הדפדפנים נותרו עם 4 עד 5 שניות (בחומרה הנ\"ל).


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

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

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

אז למה לדחות?
למה עלינו לדחות את שיפור הביצועים? כדי להתמקד בדברים יותר קריטיים מוקדם יותר:
האם ה Software Design מוכיח את עצמו? אם השקעתי יום בשיפור הקוד והדזיין לא טוב – זהו יום מבוזבז. האם המוצר בכלל מעניין לקוחות ומצליח להמכר? אם שיפרתי ביצועי קוד עשרות פעמים עד השחרור כדי לגלות שייצרתי מוצר לא מעניין (אך מהיר) – אלו עשרות ימים שהלכו לפח. גישת האג\'ייל מפרטת את הנושא הזה בצורה יסודית.
עוד נקודה היא קריאות הקוד: קוד אופטימלי הוא לרוב פחות קריא. נקודה זו רק מחזקת את הנקודה הקודמת – לא ארצה להשקיע בקריאת קוד קשה לקריאה במשך זמן פיתוח רק בכדי לגלות שהמוצר לא מעניין.
נקודה חשובה אחרונה היא עקרון פארטו שמתאר יפה מאוד את תחום הביצועים התוכנה: 80 אחוז מהשיפורים יושגו ב 20 אחוז מאזורי הקוד. אולי אפילו יותר. להשקיע ולהקשות את הקוד לקריאה ב 100% מהאזורים של הקוד – זו פשוט השקעה לא משתלמת. וב Performance כמו ב Performance יש תמיד הפתעות. שיפור במקום אחד יכול לפתוח מספר צווארי בקבוק ולהשיג שיפור משמעותי מאוד בעוד ששיפור אחר שנראה נהדר על הנייר לא ישפיע כ\"כ בפועל כי הקוד ייתקע במקום אחר. חשוב מאוד לבצע pilots של שיפורים ולעשות profiling שוב ושוב בתצורות שונות בכדי להבין את התנהגות ביצועי המערכת.

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

** כדי להשתמש ביחידות אלה יש לכתוב קוד ל instruction-set מיוחד, כגון CUDA. עקרון זה של כתיבת קוד כללי ל GPU נקרא GPGPU.



*** במקור המילה Hacker הייתה תיאור כבוד יקר-ערך. האקרים היו אותם מומחי מחשבים, יחידים במינם, שהבינו לעומק את ה Linux Kernel, דקויות של פרוטוקולי תקשורת וידעו לכתוב קוד יעיל שמתקיים על כמעט-אפס זיכרון או פעולות מעבד. מאז מחולקים באינטרנט כלים אוטומטים לפירוק אתרי-ענק לגורמים, שלא דורשים יותר מהקלדת כתובת ה IP של הקורבן. ההאקרים קראו למשתמשים אלו Script Kiddies בקול מלא בוז – אך השם לא כ\"כ תפס. על כל האקר אמיתי שמפצח פירצה וכותב ספרייה לנצל אותה, יש עשרות אלפי Script Kiddies שזכו בתהילה. טננבאום, ה\"אנלייזר\", הוא דוגמא טובה. עצוב.

תקשורת: מיהו התוכי האמיתי של האינטרנט המהיר?

הצחיק אתכם התוכי של בזק שנוסע במרכז ת\"א במסלול משלו?

זו פרסומת טובה. המסר מוחשי ומובן לכולם. בזק מתארת בפרסומים \"רשת נפרדת\", אך לא ברור מה בדיוק היא מספקת בפועל.עד כמה שידוע לי זהו routing מועדף (על בסיס static IP address) ויותר רוחב פס – לא יותר. אין שום רשת פיסית נפרדת – ואם הייתה, היא בוודאי לא הייתה נפרשת לכל קצוות תבל.

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

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

כנראה שתמונת האינרנט לא תהיה שלמה ללא הכרות עם חברת Akamai.
אקמיי (Akamai) חברה מסחרית היושבת במדינת מסצ\'וסטס (זו שקשה לומר את שמה) אחראית לנתון מדהים של 15 עד 30 אחוז* מתעבורת האינטרנט העולמית!
היא עושה זאת בעזרת 90 אלף שרתים המפוזרים ב 1800 אתרים (נכון למידע העדכני שמצאתי באינטרנט – והמספר רק גדל)
מי שמשלם על השירות הוא חברות האינטרנט שרוצות לספק תוכן מהיר (Apple, CNN, MTV ועוד). הרשת של Akamai אינה רשת פיסית (כמו כל דבר כמעט באינטרנט…) אלא רשת ווירטואלית ומשתמשת בעיקר בטכניקות הבאות:

Caching 
Akamai מבצעת Caching (דינאמי, שעם הזמן יכול להיות העתק של השרת המקורי) של תוכן משרת הלקוח לשרתים רבים ברשת שלה שפזורים בכל רחבי העולם. המשתמש שפונה לאתר הלקוח מופנה (ללא ידיעתו) לשרת הקרוב אליו גאוגרפית של Akamai.
אם התוכי של Akamai לא היה מביא את הסרט שאתם מורידים (אופס, כתבתי את זה?) לישראל או הסביבה – שום תוכי של בזק לא היה משיג 100Mbps בהורדת התוכן.
\"אבל חלק גדול מאוד מדפי האינטרנט הוא דפים דינאמיים\" יטען מפתח האינטרנט. נכון, אבל יש תמונות וקבצי מדיה (וידאו הוא כמעט חצי בכל תעבורת האינטרנט בבתים) שניתן לעשות caching בקלות ויש גם דרכים לבודד אלמנטים מהתוכן הדינאמי שלא משתנים ולשמור אותם ב cache.

Remote Proxy
למי שזוכר קצת תאוריה, יצירת קשר ב tcp (או http) דורשת 3 קריאות IP (הידוע כ three way handshake) ואם רוצים תוכן מאובטח (ssl) – עוד 4 קריאות handshake נוספות. במצב בו כל קריאת http/s מייצרת connection חדש – יעברו 3 או 7 הודעות ברשת בין השרת והלקוח עד שעמוד האינטרנט יתחיל לרדת (= latency). אקמיי יודעת להחזיק connection קבוע בין השרת של הלקוח לשרת המקומי שלה, לתת למשתמש לבצע handshake מול השרת המקומי שלה ומשם להשתמש ב connection קבוע. טכניקה זו פחות נדרשת עם העליה בתמיכה בפרוטוקול http 1.1 שהסדיר את שמירת ה connection הקיים בעזרת keep alive או pipelining. עדיין – פתרון מעורר מחשבה.

Improved Routing
Akamai טוענת שיש לה אלגוריתם גאוני (הרי הוקמה ע\"י בוגרי MIT, שאחד מהם, ישראלי, דני לוין נהרג בפיגועי 9/11  תוך מאבק בחוטפי אחד המטוסים***) ל routing משופר ברחבי האינטרנט, שמגיב גם הרבה יותר מהר לתקלות בתשתית התקשורת העולמית. עם פריסה ב 1800 אתרים ושליטה מרכזית בהם ייתכן שהיא צודקת (למרות שמבחנים הראו רק שיפור קל, בממוצע, על ה routing של האינטרנט עצמו).

Data Compression

יש חברות (CDN (Content Delivery Network אחרות (Akamai היא הגדולה, אך בהחלט לא היחידה) שמבצעות דחיסה יעילה במיוחד של תוכן דינאמי בין שרת הלקוח לשרת המקומי – לשיפור התעבורה. בוודאי יש עוד טכניקות רבות בשימוש…
ספציפית דחיסה נראית לי שיטה שלא תחזיק זמן רב בהתבסס על חוק נילסן: החוק שאומר שאמנם מעבדים מכפילים את כוחם כל 18 חודשים (חוק מור), אך הרשת מכפילה את קצב ההעברה פי 100 כל עשור (שזה יותר) – ולכן מתישהו (אנחנו עדיין מחכים) תשתנה הפרדיגמה ויהיה עדיף להעביר יותר תוכן ברשת בכדי לחסוך cycles של המעבד.

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

העתיד
כיום כבר יש לא מעט חברות CDN, אני מודע לאחת משלנו (קונטנדו הישראלית) והתחרות גוברת. Akamai שהבינה שהיא מאויימת על ידי רשתות P2P לגיטימות שצצו בשנים האחרונות (שהן זולות יותר ובעלות scale פוטנציאלי גדול יותר), התחילה לפעול גם בזירה הזו. Akamai מספקת Download Manager שאמור לשפר מהירות הורדה מאתרים מסוימים, אבל בעצם משתף את ההורדה P2P עם גולשים קרובים גיאוגרפית ששותפים לאותה ההורדה.
מאחר וחברות אבטחה הוסיפו למוצרהם יכולות CDN (דוגמא ישראלית: אינקפסולה**), הלכה Akamai והוסיפה יכולות אבטחה (בסיסיות) לשירותי ה CDN שלה. בזכות מערך השרתים האדיר השלה היא הצליחה לעצור ביולי 2009 התקפת DDoS אימתנית בקצב של 124Gbps על גוף ממשלתי בארה\"ב – קצב שהיה מפיל חברות רבות שנותנות שירותים דומים. בקיצור – נשמע שתהיה פה עוד נגיסה הדדית בין תחום האבטחה לתחום ה CDN.

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

עדכון: ניתן למצוא סיכום עברי על דו\"ח מצב האינטרנט של Akamai כאן.


* תלוי ב יום / שעה.

** כצפוי, אינקפסולה מספקת אבטחה חזקה מזו של Akamai, כמו ש Akamai מספקת CDN טוב בהרבה מזה של אינקפסולה.

*** תודה ל Kalen מאתר HWZone על הלינק לוידאו.