RESTful Services – שירותי הרשת של המחר, החל מאתמול (1)

פוסט ראשון מתוך שניים. את ההמשך אפשר למצוא כאן.

REST הוא עוד באזז של השנים האחרונות: חברות אינטרנט רבות אימצו אותו, ספרים רבים נכתבו, גוגל יצרה וריאציה משלה בשם GDATA ומנסה להפוך אותו לסטנדרט. מייקרוסופט מצידה הגדירה אלטרנטיבה בשם [ODATA[1.

על מה כל המהומה?? – אנסה לענות במאמר זה.

מהו בעצם REST?
טוב, קחו נשימה עמוקה: REST הוא סגנון ארכיטקטוני (Architectural Style) ממש כמו Pipes & Filters, Layered Architecture או (SOA (Service Oriented Architecture.
סגנון ארכיטקטוני הוא לא ארכיטקטורה, אבל אם אתם יודעים מהו הסגנון הארכיטקטוני של מערכת (וגם הסגנון הזה נשמר לאורך הפיתוח) – תוכלו לדעת דיי הרבה על איך המערכת נראית ומה העקרונות שעומדים בבסיסה. ממש כמו שאם אתם הולכים לראות מבנה שאתם יודעים שהוא בסגנון גותי, סיני או ערבי – תדעו פחות או יותר למה לצפות.

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

REST הוא סט חוקים שמערכת יכולה לבחור ולאמץ. ב High Level הוא אומר שני דברים עיקריים:

  • תיאור ממשק המערכת כעולם של Entities (כ"א instance של אובייקט) כבעל מזהה (URL) ייחודי, דרכו ניתן לבצע פעולות. ממערכות כאלו נקראות Resource-Based Distributed System – שכל entity הוא כאילו משאב מסמך עצמאי עליו עושים פעולות[2].
  • הצמדות מדויקת לפרוטוקול HTTP – פרוטוקול שיש בו הרבה חוכמה שאנו נוטים לפספס.
ה API שנחשף החוצה, הוא התוצר – לא העיקר.

איך אני יודע אם אני משתמש ב REST

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

על מנת להשתמש ב REST API (נקרא גם RESTful Service) לא צריך לדעת כמעט שום דבר: פשוט פותחים connection של HTTP, שולחים פרמטרים ע"פ התיעוד של ה API ומקבלים תשובה בפורמט שתואר.
מצד אחד קצת חבל שכמעט כל מי שמשתמש ב REST לא מודע לעקרונותיו היפים, אבל מצד שני: היי – זה דבר נהדר! הכמסה (Encapsulation) במיטבה! אל תסבכו את הצרכן שלכם בידע מיותר.

אז…הדרך הנפוצה לדעת אם אתם צורכים ב REST הוא לקרוא האם בתיעוד כתוב "REST" ולקוות שמי שכתב את התיעוד מבין על מה הוא מדבר : )

אם אתם כותבים מערכת REST, יש הרבה מה לדעת – המשיכו לקרוא.

קצת היסטוריה

תחום האינטגרציה של מערכות ארגוניות (EAI – Enterprise Application Integration) הוא תחום מסובך ויקר במיוחד. רכשת מערכת כספים מספק א' ומערכת ניהול קשרי לקוחות מספק ב' – על מנת לנצל את היתרון שהמערכות ממוחשבות וניתן להצליב בניהן נתונים, אתם צריכים לגרום למערכות לדבר אחת עם השנייה. בגלל שהמערכות מדברות בשפה (Conceptual Model) שונה ובגלל שהארכיטקטורות שלהן שונות – המאמץ הוא אדיר. כשאנחנו נזכרים בסיפורים בהם משרדי ממשלה לא מצליחים להצליב נתונים (ביטוח לאומי ומס הכנסה, או ארגוני ביון אמריקאים לפני שנת 2001) אנו נוטים לחשוב שזהו מצב של חלם, אבל בפועל עלות האינטגרציה היא אדירה ולעתים קרובות עולה על מחיר המערכות עצמן[3].

כך נראה פרוייקט EAI של ארגון בגודל בינוני

בתחילת שנות האלפיים חברו כמה חברות בראשן BEA, Microsoft, IBM ו SAP ליצור סטנדרט בתעשייה שיקל על פעולות האינטגרציה של מערכות. תקן זה ידוע כ "Web Services" הכולל Stack של פרוטוקולים שהעיקריים שבהם הם: SOAP, WSDL, UDDI ו XML (שהיה כבר קיים אך אומץ ע"י הסטנדרט). תוך כדי התפתחה מאוד ההתעסקות ב (Service Oriented Architecture (SOA. העיקרון אינו חדש: זה תיאור של מערכת מבוססת services ו מבני נתונים המחזיקים את המידע העובר בין ה services, ממש כמו שתכנתנו פעם בפאסקל או C. גם היום חלק גדול ממערכות ה .NET וה Java בנויות כך, לעתים מתוך החלטה, לעתים "כי פשוט יצא ככה". החידוש ב SOA היה הידע שנצבר והתפתח עבור אותה פרדיגמה במערכת מבוזרת.

יוצרי ה Web Services היו זקוקים לשם מפוצץ ("SOA") וצבא של יועצים-מומחים בכדי לשכנע את השוק לאמץ את גישתם. על פני השטח זה נראה כמו וויתור על פרדיגמת ה Object-Oriented (אותה, אותם יועצים ממש, מכרו כמה שנים לפני כן כ "חובה לכל ארגון") וחזרה לסגנון התכנות הפרוצדורלי (ברמת המערכת) שהיה שם קודם לכן. הם ניסו לשכנע שזו לא התדרדרות אחורה – אלא התקדמות קדימה. האמת – הם צדקו [4].

עם השנים (כמה שנים בודדות, לא יותר) תקן ה Web Services הסתבך לעשרות תקני משנה, הידועים כ WS-* (כוכבית = wildcard כמו WS-RPC, WS-Security וכו') שניסו לפתור עוד ועוד היבטים של אינטגרציה בין מערכות תוך כדי שהם נהיים מורכבים יותר ויותר לשימוש. קשה היה לאדם בודד להכיר את כל התקנים ובטח לא להתמצא בהם. בעיה נוספת הייתה performance: בגלל שהתקן מאוד כללי (בנוי לקשר בין מערכות מספקים שונים, הכתובים בשפות תכנות שונות ובין גרסאות שונות) ובגלל שהוא מבוסס על קבצי XML גדולים, פורמט המרבה במילים (verbose) – תקשורת מבוססת Web Services הייתה צוואר בקבוק גם של הרשת, אבל בעיקר של צריכת זיכרון (בשל ה parsing של קבצי xml ענקיים). עניין זה היה מטרד למערכות ארגוניות, ומכת מוות למערכות אינטרנט High Scale.

חברות האינטרנט הקטנות והיעילות יצאו למלחמה רבתי: "REST נגד SOA" – ראה [5]
הם הציגו את REST כאלטרנטיבה פשוטה, מהירה ונוחה למתכנת לייצר Web Services. הם גם נתנו לשירותים אלו שם מפוצץ משלהם: "RESTful Services". אני זוכר שהייתי בכנס QCON בלונדון בשנת 2008, ורבים מה sessions היו על נושאים ב REST או ב SOA (למשל, אני זוכר session שנקרא "REST eye for a SOA guy"). כל פעם באו אנשי המחנה השני, קראו קריאות ביניים והפריעו למרצה ב Session. מהר מאוד למדתי להדיר רגלי מכל Session באחד משני הנושאים הללו.

מכיוון שפוסט זה עוסק ב REST ולא ב Web Services אתם יכולים להסיק, בצדק, ש REST ניצחה במלחמה. השימוש ב Web Services הצטמצם משמעותית ונותר בעיקר בנישה של מערכות שונות של ספקים שונים. אפילו החברות אשר יזמו וקידמו ללא ליאות את הסטנדרטים (עבדתי ב SAP – אני יודע) הוציאו הנחיות פנימיות לצמצם שימוש ב Web Services למינימום ההכרחי.

הפשטות ניצחה את ה Coverage.

הבנת ההבדל בין Web Service ל REST
גם REST וגם Web Service הם אמצעי תקשורת בין מערכות שונות המבוססים על XML העובר על [HTTP[6 – היכן ההבדל הגדול?

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

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

getOrderDetails()
updateOrder()
Subscribe()
cancelSubscription()
findMatchingOrder()
listOrderProviders()

פונקציות כמו ()Subscribe או ()ListOrderProviders אינן קשורות בדיוק להזמנה, הן בתחום. את ה interface השירות חושף בעזרת XML שנקרא WSDL כך שמי שצורך אותו יוכל בקלות לבצע import ל IDE אשר ייצר proxy לוקלי לקריאה לשירות כאילו מדובר באובייקט מקומי. Visual Studio, כבר מימיו הראשונים של .NET עושה זאת בצורה נהדרת.
כאשר מתבצעת קריאה ל Web Service בפועל, נוצר XML עם הפרמטרים הרלוונטיים. XML זה נעטף ב XML נוסף הנקרא Envelope של פרוטוקול ה SOAP (ה envelope מוסיף נתונים העוזרים ל cross platform interoperability אך ייתכן ויהיה גדול משמעותית מההודעה עצמה). אם ה Web Service תומך או דורש שימוש בכל מיני שירותים נלווים (WS-* למיניהם) יש להתייחס אליהם וייתכן שהם יוסיפו תוכן או ישנו את צורת ההתקשרות.

RESTful Web Services
REST, כפי שאמרנו, מתאר Resource-Based Distributed System. הגישה היא ל resource (או האובייקט) עצמו ולא לשירות. לרוב מדובר על המון משאבים (הממופים כ"א ב URL), אשר כל כ"א סט מצומצם וקבוע של פעולות המוגדרות  בפרוטוקול HTTP.

על מנת לקרוא את פרטי ההזמנה אבצע קריאת HTTP GET ל URL:

על מנת לעדכן את ההזמנה אבצע קריאת HTTP PUT ל URL:

את נערכים שאני רוצה לעדכן אשלח כ Post Parameter בפורמט XML או JSON הכולל את הערכים הרלוונטיים.
על מנת לבצע שאילתה על כל ההזמנות בשנת 2009 של לקוח AMEX אני אבצע קריאת HTTP GET ל URL:

האובייקט הוא orders, אני מבצע קריאה ושולח פרמטרים ל Query בשם year ו customer.

כמובן שאני לא יכול לשלוח מה שבא לי – רק מה שהוגדר ע"י ה שAPI ומתועד ב API Documentation.

ועל מנת לבצע שאילתה של listOrderProviders נגשים ל"אובייקט" ה OrderProviders, כמובן:

אם ביצעתי קריאת GET להזמנה שאינה קיימת אקבל כנראה שגיאת HTTP 404, המוגדר בפרוטוקול HTTP כ "Not Found". אם ביצעתי קריאת POST (הוספת ערך חדש) אצפה באופן טבעי לתשובת HTTP 201 המוגדרת בפרוטוקול HTTP כ "Created". עבור ביצוע אסינכרוני אצפה ל 202 "Accepted" וכו'

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

קשה לי לתאר במילים כמה פרוטוקול REST פשוט יחסית לפרוטוקול WS-*. אחד הטיעונים נגדו היה שזהו Hack שלא יחזיק מים במערכות גדולות ומורכבות (טעות). פעם בקורס על Web Services ב SAP ישבנו שעתיים רק לסקור את סוגי השירותים השונים של WS-* וזה היה על קצה המזלג.

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

המשמעות של הוספת RESTful API למערכת קיימת שאינה בנויה בצורה REST-friendly היא לרוב להוסיף שכבת Adapting עשירה או לא להצליח להנות בפועל מיתרונות ה REST. ייתכן וכל מה שאתם מחפשים הוא לחשוף API בצורה שהמשתמשים רגילים (REST like) ולכן יתרונות ה REST האחרים הם לא חשובים. לגיטימי.

הקשר בין REST לפרוטוקול ה HTTP וארכיטקטורה של Resource-Based Distributed System אינו מקרי.
בפוסט ההמשך ארחיב על נושאים אלו יותר לעומק.

[1] Open Data. מכיוון שהצלחה נראתה כיעד אסטרטגי מהותי – היא שיחקה עם גוגל במגרש שלה, פתחה את התקן כ Open Source ושחררה ספריות התומכות ב .NET כמובן, אך גם PHP, Java ו JavaScript.

[2] היסטורית מקובל לחלק מערכות מבוזרות ל 4 סוגים:

  • Object-Based Systems: מערכות שמאפשרות לגשת מרחוק ולהפעיל אובייקטים עשירים בפרדיגמת Object-Oriented. דוגמאות הן Corba, DCOM או EJB כאשר עובדים עם Remote Interface.
  • Distributed Database / Storage System – כאן נכנסים כל מערכות ה NoSQL שתיארתי בפוסט על Big Data או מערכות קבצים מבוזרות נוסח Gopher, WebDAV או HDFS ו GFS המודרניים.
  • Distributed Coordination-Based Systems: מערכות תיאום מבוזר כמו Rendezvous או Jini של ג'אווה שנכשל ונולד מחדש כ Apache River. דוגמה מודרנית יכולה להיות פרוטוקול Gossip או מערכות peer 2 peer.
  • ומה שחשוב לפוסט זה: מערכות Resource-Based (לעתים נקראים גם "Document-Based") מבוזרות אשר ניגשים ל Resources ("מסמכים") אחד אחד לצורך פעולות קריאה, כתיבה וכו'. דוגמה אחת: האינטרנט (מסמכי HTML). דוגמה שנייה: מערכות REST.

[3] זה הסיפור העיקרי עליו מבוססת מכירת מערכות ERP של חברות כמו SAP או Oracle: "אין לנו את ה CRM הטוב ביותר או ה SCM הטוב ביותר – אבל אתה קונה את האינטגרציה built-in".

[4] שנים רבות Object Oriented Programming נחשב לשם נרדף לקדמה ומקצועיות, אבל בפועל הוא לא היה Silver Bullet – כלומר לא הביא לשיפור חד משמעי בעולם התוכנה. לתכנות פרוצדורלי יש הרבה יתרונות ונראה שיש לו עוד מקום של כבוד בעולם התוכנה בשנים הבאות. כמובן שעדיף להבין את היתרונות והחסרונות המעשיים של כל גישה ולבחור בחירה מודעת. סימן אחד לכוחה של הפרדיגמה הפרוצדורלית היא שהרבה מאוד פרויקטים שניסו לייצר מודל OO כשלו וגמרו עם מודל פרוצדורלי. כלומר: OO הוא קשה למימוש, פרוצדורלי הוא קל. חישבו על כך – זהו יתרון משמעותי.
תכנון מונחה עצמים Object Oriented Design, לעומת זאת, הוכיח את עצמו יפה והוא מוצלח משמעותית מכל מיני פרדיגמות עתיקות כמו DFD (השם ירחם!) או ERD שנהגו להשתמש בהם בשנות השמונים (או בסוף שנות התשעים באקדמיה – אותה תקופה בה למדתי את התואר הראשון). יהיה זכרם ברוך.

[5] SOA היא ארכיטקטורה טובה, הם בעצם התכוונו לצאת נגד Web Services. עקרונית REST הוא סוג של SOA.

[6] REST לא מגדיר מה פורמט ההודעה, XML נפוץ מאוד וכך גם JSON ואפשר גם להשתמש בפורמט אחר כלשהו.

מה הביג-דיל ב Big Data? (או NoSQL)

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

פעם (לפני כעשור), מערכות ה High Scale היו בעיקר מערכות ה Enterprise המיועדות לארגונים גדולים. לחברת Siemens יש 120,000 משתמשים (users)? וואהו – אתגר ארכיטקטוני מרשים. מערכת המסחר של וול סטריט מבצעת מאות פעולות (transactions) בשנייה אחת? – בלתי נתפס!
חברות ענק כמו SAP, Oracle ו IBM הן אלו שבד\"כ התמודדו עם אותם scales , בעיקר בזכות העובדה שאותם לקוחות-ענק קנו מערכות מורכבות שיצרנים אלו סיפקו. יצרן קטן – scale קטן, יצרן גדול – scale גדול.

מאז שנת 2000 האינטרנט פרץ למיינסטרים. מוצרים כמו MySpace ו SecondLife ואח\"כ Facebook ו Youtube עקפו בסיבוב את חברות הענק וטיפלו במיליוני משתמשים, petabytes של שטחי אחסון ואלפי (tps (transactions per second. בהדרגה, עוד ועוד חברות קטנות נאלצו להתמודד עם scales אדירים. הכלים להתמודד עם כמויות גדולות של נתונים (כמו פתרונות של Teradata וOracle) גם היו יקרים מדי עבור אותן חברות קטנות, וגם לעתים לא עמדו בקיבולת המבוקשת – וכך אותם ארגונים החלו לייצר חלופות זולות ויעילות להתמודדות עם scale ענק. לא סתם Facebook, Amazon או Twitter שרדו מבין חברות דומות (שלעולם לא שמענו או נשמע עליהן). מלבד הרעיון המגניב, היה צריך להתמודד עם אתגרים טכנולוגיים יוצאי-דופן. רעיון מגניב + ניהול נכון + מצוינות טכנולוגית הוא שילוב נדיר אשר היה דרוש להצלחה.
בסולם ה Scale הוגדר ערך חדש הגבוה מהערך הגבוה הקודם (\"High Scale\"). מעתה, אמרו \"Internet Scale\".

הבעיות
הערה:כמו שצוין למעלה, ב Big Data יש עניין מוצהר – טיפול בכמויות אדירות של נתונים, ועניין לא מוצהר, אך לא פחות חשוב – פתרון זול המתאים גם לחברות קטנות. עדיף Open Source, עדיף מאוד Commodity Hardware (שרתים במחיר של, נאמר, עד 10K$ כל אחד)

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

הגדילה בתעבורה של אתר Netflix כמו שדווח על ידם

כאשר יש לכם כמויות גדולות של נתונים, אתם צריכים:

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

למרות ש MySql (או כל בסיס נתונים רלציוני) הוא מוצלח, ישנו גבול של נתונים שהוא יכול לטפל בו. הגדילה הראשונה היא כנראה לקנות שרת יותר חזק (vertical scalability הקרוי גם scale-up). השרת יטפל בפי n כמויות מידע ויעלה לרוב משמעותית יותר מפי-n.
השלב הבא, ברוב בסיסי הנתונים, הוא ליצור cluster של בסיסי נתונים (horizontal scalability הקרוי גם scale-out), בחוות שרתים שלכם או ב Cloud.
איך מטפלים בכפילות מידע? דרך אחת היא ששרת אחד מוגדר לכתיבה בלבד (ומעדכן את השאר) ושאר השרתים רק מבצעים שאילתות קריאה ומשחררים עומס מהכותב. כמו שאתם מבינים זהו בסה\"כ קצת אוויר לנשימה.
Partitioning של המידע: לאחסן על כל בסיס נתונים (או cluster כמתואר למעלה) פלח מידע שונה, לדוגמה: פילוח ע\"פ מדינות, אות ראשונה בשם המשתמש וכו\"
offloading to data warehouse – מדי כמה זמן להעביר את המידע שאליו ניגשים פחות (לרוב מידע ישן) לבסיס נתונים אחר (\"מחסן\") כדי לגרום לבסיס הנתונים עליו המידע החשוב להיות זמין יותר.

בשיטת ה Partitioning יש שתי בעיות עקרוניות:
א. אם מפצלים נתונים לשרתים שונים, יש להתפשר או על זמינות (availability) או על עקביות הנתונים (consistency) – עקרון הידוע כ CAP Theorem (כלומר – ללא ACID).
ב. שאילתות הכוללות מספר בסיסי נתונים אחד הן מורכבות למימוש ואיטיות במיוחד (במיוחד אם דורשות נעילות). למרות שלספקי בסיסי הנתונים היו שנים רבות ללא תחרות קשה בתחום – הם לא פיתחו את התחום בצורה משמעותית.

Big Data
אותן חברות סטארט-אפ שלא יכלו לשלם על פתרונות יקרים ונזקקו לכלים לטפל בכמויות אדירות של נתונים פיתחו כמה מהפלטפורמות הבאות שרובן הגדול זמין כיום כ Open Source (מסודר ע\"פ תחום):

  • CPU – לרוב אין צורך בפתרון מיוחד. מקימים Cluster עם שרתים זהים ובעזרת Load Balancer מחלקים לכל אחד מנה מהתעבורה. פתרון שקיים כבר שנים.
  • אחסון פיזי: S3 של אמזון, GFS של גוגל או HDFS* של אפאצ\'י (היחידי שזמין לקהל הרחב).
  • אחסון לוגי: אלו בסיסי הנתונים המפורסמים (הסבר בהמשך) השייכים לאחת מארבע קטגוריות:
    • Document Oriented
    • Columnar DB
    • Graph Database
    • Key-Value DB
  • יכולת לבצע שאילתות מבוזרות: Hive, Hadoop Map-Reduce, Cascading, MrJob ועוד.
בסיסי נתונים NoSQL

פירוש השם NoSql התחיל כ \"לא צריך SQL\", אולם עם הזמן התפכחו הדוברים והבינו שאין כאן Silver Bulltet – לרוב המקרים בסיס נתונים רלציוני עדיין מתאים. היום ההסבר השגור לשם הוא: \"Not Only SQL\". 
הרעיון פשוט למדי: בסיסי הנתונים הרלציונים הם עשירים ומורכבים: הם מאפשרים שאילתות SQL מורכבות (שאילתות מקוננות, סיכומים סטטיסטים ועוד), הבטחת פעולות ACID**, אכיפה של constraints, טריגרים ו Stored Procedures ועוד. מה היה קורה אם היינו מוותרים על רוב היכולות ומתמקדים רק במערכת היכולה לטפל ב Scale מרבי למקרה הספציפי? 
Disclaimer: ההסברים הבאים הם קצת פשטניים, אבל עדיין יכולים להסביר הרעיון העיקרי עליו מבוססת כל קטגוריה של בסיס נתונים NoSql-י.

Document Oriented DB
לעתים קרובות אנו רוצים לייצג רשומות היסטוריות רבות: לדוגמה סיכום עסקאות ברשת סופרמארקט.
אם נלך לפי העיקרון האקדמי של בסיס נתונים רלציוני ומנורמל תהיה לנו כנראה טבלת סניפים (נאמר 20) המקושרת לטבלת עסקאות (נאמר מיליון בשנה, עשר שנים = 10 מיליון), המקושרת לטבלת פריטים בעסקה (Line Item), נאמר 20 בממוצע בעסקה.
טבלת הפריטים של כל המערכת תהיה בגודל של 4 מיליארד רשומות. כלל האצבע בבסיסי נתונים הוא שמעל 10 מיליון רשומות בטבלה – בסיס הנתונים מתחיל להגיב לאט. כלומר-  לא מעשי. בנוסף הכנסה מקבילית של הרבה קופאיות לאותן טבלאות (מקושרות) ייצור רצף נעילות שיגביל מאוד את המערכת (עוד קצת על מקביליות ונעילות – בתחתית הפוסט) מצד שני אנחנו יכולים לקחת את ההנחות המקלות:
  • אנו שולפים או שומרים כמעט תמיד עסקה בודדת – ואנו רוצים ששליפה זו תהיה מהירה.
  • שאילתות רחבות הן נדירות ואנו מסכימים שיקחו הרבה מאוד זמן.
פיתרון קיים (יצא לי פעם להתנסות בו) הוא במקום טבלת הפריטים – לייצר בטבלת העסקאות עמודה מסוג \"string\" המכילה XML או JSON עם פרטי העסקה. זהו שיפור משמעותי ב scale, מכיוון שיש לנו פחות rows, פחות אינדקסים לתחזק ופחות joins להריץ. מצד שני יש יותר custom code שצריך לכתוב – עבור דברים שהיינו מקבלים קודם בשאילתה. יתרונות אחרים של גישת ה Document Oriented DB הן שניתן לשנות את הסכמה מבלי לבצע Alter table יקר ואם ישנן עמודות דלילות ב DB – לא נבזבז עליהן מקום מיותר (מה שנקרא Semi-structured data).
בסיסי נתונים Document Oriented נותנים פיתרון מובנה לעקרון זה שכולל לרוב API פשוט לשימוש וכלי שאילתות מבוזר נוסח Map-Reduce. דוגמאות הן MongoDB ו CouchDB. במקום להמציא את הגלגל – קחו Open Source.
Columnar DB
קטגוריה זו, הידועה גם כ Vertical DB פותרת בעיקר בעיות של Data Warehousing: איך לבצע שאילתות יעילות על מחסני נתונים. דמיינו טבלת ענק עם 10 עמודות בגודל x בתים (bytes) כל אחת.
לרוב בשליפות ה SQL אנו שולפים עמודות בודדות. אם הרצתי שאילתה על 3 עמודות, בסיס הנתונים עדיין צריך לקרוא מהדיסק לזיכרון את כל עשרת העמודות – כלומר פי 3 מידע ממה שנדרש. הקריאה מהדיסק היא הפעולה היקרה. אם הייתי מאחסן כל עמודה בקובץ נפרד בדיסק, אולי הייתי מוגבל בשאילתות מורכבות מאוד, אולם השאילתות הפשוטות היו דורשות משמעותית פחות עבודה של הדיסק.
במחסני נתונים, לעתים קרובות, רוצים לבצע חישוב ממוצע / התפלגות ערכים / whatever על עמודה בודדת (ומספרית) מתוך טבלה הכוללת הרבה עמודות שחלקן הגדול הוא מחרוזות (התופסות נפח גדול בהרבה). היכולת לטעון מהדיסק עמודה בודדת יכולה להאיץ את ביצוע השאילתה בעשרות מונים.
דוגמאות בולטות הן Vertica או InfoBright. חברת SAP זכתה לתשואות כאשר באופן מפתיע הצטרפה לחגיגה עם HANA – גרסה In-Memory של בסיס נתונים columnar. כולם פתרונות שאינם open source.
Graph DB
בסיסי נתונים רלציונים הם גרועים במיוחד בתיאור גרפים. נניח שהייתם מפתחים אפליקציה כמו LinkedIn והייתם רוצים לדעת מה הקשר בין שני אנשים, מתוך מאגר של 100 מיליון משתמשים.
ישנו כלל מקל האומר שכל שני אנשים מקושרים ע\"י שרשרת של 6 הכרויות. מה נעשה? Join משושה של 100 מיליון משתמשים?? קחו טיול חצי שנה לדרום אמריקה לפני שהשאילתה תסתיים***.
אם היה לכם בסיס נתונים שמייצג גרפים בצורה נבונה, ייתכן והוא היה יכול לעשות שאילתה כזו בפחות משנייה. יש הרבה שימושים ואלגוריתמים נוספים לגרפים שבסיסי נתונים אלה מספקים.דוגמאות בולטות הן Neo4J ו HyperGraphDB.
Key-Value DB
האם הייתם רוצים להשתמש ב HashTable בגודל של מיליארדי רשומות – שגם יאפשר מקביליות גבוהה? כמה נוח. Key-Value DB יספקו זאת, רק אל תבנו על (O(1 בזיכרון. זוהי פרדיגמה פופולרית במיוחד בקרב חברות אינטרנט:
גוגל יצרה את BigTable ושחררה מסמך מפורסם החושף ארכיטקטורה מהפכנית, אמזון יצרה את Dynamo ושחררה מסמך מפורסם אחר – לא פחות מרשים.
פרויקט Hadoop מימש את התכנון של גוגל ויצר את HBase ו LinkedIn מימשו את התכנון של אמזון ויצרו את Voldemort (כן, הנבל מהארי פוטר).
פייסבוק ערבבה רעיונות של גוגל ואמזון ויצרה את Cassandra שזוכה להצלחה רבה. יש גם את Redis שהוא In-Memory Database המבוסס על אותה פרדיגמה.

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

עדכון 1: תודה ליקיר שהזכיר את RavenDB, בסיס נתונים Document Oriented עבור פלטפורמת .NET שפותח בארץ ע\"י אורן עיני – מפתח ישראלי בולט.

עדכון 2: ripper234 העיר ובצדק (בפרסום ב newsgeek): \"מה שהייתי שם בפתיחה למאמר כזה שאסור להתאהב בטכנולוגיות וב-\"Big data\". פגשתי יותר מדי אנשים שהחלום הרטוב שלהם זה Big Data / NoSql / Technology Buzzwords, אבל שוכחים בדרך את האג\'יליות ואת העבודה שבסטארט-אפ עובדים בשביל ליצור value אמיתי, כמה שיותר מהר, ולא מערכת מטורפת שתחזיק 100 מיליון יוזרים 5 שנים קדימה אבל תיקח שנתיים לפתח.\"

במאמר זה ניסיתי להתמקד בטעות נפוצה אחרת: המחשבה ש Big Data הוא Silver Bullet, שהוספת בסיס נתונים NoSQL תפתור תכנון בסיסי לקוי. ניסיתי להציג את אותם בסיסי נתונים ולהסביר \"מה הטריק שלהם\", כי לפעמים בצורה מאוד נקודתית ניתן לממש את הטריק הזה לבד ללא מעבר full-fledged לבסיס נתונים שכזה.

* Hadoop Distributed File System השייך לפרויקט העל Hadoop. השם Hadoop הוא שמו של פיל-הצעצוע האהוב של בנו הקטן של מפתח הפרויקט – ומכאן לוגו הפילון.

**  ACID – Atomic, Consistent, Isolated and Durable הרי הן ה transactions.

*** סתם. ה DB יקרוס אחרי כמה עשרות דקות.

על הדרך הנכונה לחלק מערכת לשירותים מבוזרים

המערכת שלכם, הרצה על שרת יחיד (או ב cluster שבו כל ה nodes זהים), גדלה והחלטתם להרחיב אותה ל 2 או יותר שירותים (services) עצמאיים על שרתים נפרדים. במאמר זה אסקור כמה שיקולים חשובים במהלך שכזה.

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

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

חלוקה של מערכת (process או service) למספר תהליכים או שירותים – הוא גם צעד שלא טומן בחובו Tradeoffs משמעותיים. לרוב – ה tradeoff בין צריכת זיכרון ל isolation – שבמקרים רבים עושה שכל.

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

אפשרויות הביזור
הפיצול לשירותים לעיתים מבטא שיקוף של המבנה הארגוני: שירות אחד של צוות X על שרת A, ושירות אחר של צוות Y על שרת B. בתאוריה של מערכות מבוזרות, מערכת כזו נקראת מערכת מבוזרת הטרוגנית.

מערכת מבוזרת הטרוגנית

אפשרות פעולה אחרת היא שגם שירות X וגם שירות Y נמצאים על שרתים A וגם B כך שתכולת שרתים אלו היא זהה. אפשרות זו נקראת מערכת מבוזרת הומוגנית

מערכת מבוזרת הומוגנית

מתי לבחור פרדיגמה הומוגנית?

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

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

יתרונות:

  • זמינות (high availability) גבוהה יותר, מכיוון ששני השרתים זהים. שרת A נפל – שרת B יוכל לספק את כל השירותים. בפרדיגמה ההטרוגנית כל שרת הוא single point of failure.
  • ניהול עומס (load balancing) מיטבי – כל שרת יכול לטפל בכל בקשה וכך ניתן לחלק את העומס בצורה מיטבית בין השרתים. בגישה ההטרוגנית ייתכן ששרת A עמוס לחלוטין, ולשרת B יש משאבים פנויים. קרי – לא ניצלתם את החומרה לתומה. חישבו על פיזור העומס לא רק ב load מרבי, אלא גם על השעות מהם יש עומס קטן יותר על המערכת.
  • יעילות תקשורת – אם שירות X ו Y זקוקים אחד לשני – הם יכולים לבצע קריאות לוקאליות בזכרון, שהן יעילות ובעלת latency קטן משמעותית מקריאה ברשת. אפילו אם בוחרים לתקשר על גבי http – הביצועים יהיו עדיפים במחשב מקומי.
  • תחזוקה קלה יותר (Maintainability). שיקול Operations. אנו יכולים להחזיק אותה חומרה ולנהל מלאי אחד של חלפים. אנו יכולים לנהל image יחיד, להתמודד עם בעיות של updates ו upgrade בצורה אחידה וכו\'.
איך ממשים שני שירותים על אותו שרת? לרוב הפתרון פשוט כמו שהוא נשמע: אם מדובר על Servlet Engine – פשוט מתקינים את שני השירותים על אותו Container כשני קבצי war או ear נפרדים (שכל צוות בארגון יכול לפתח עצמאית).
אם השירותים הם בשפות תכנות שונות (נאמר Ruby ו Scala כמו ב [1]Twitter או C ו Java כפי שנפוץ במוצרים רבים) – פשוט מתקינים שני containers או אפליקציות על אותו השרת הפיסי. הרי ב Windows או Linux יש עשרות שירותים מותקנים, אז מונע מאיתנו להריץ עוד כמה?

עד כמה שנתקלתי המחסום העיקרי לאימוץ גישה זו – הוא פסיכולוגי. אולי התבנית מזכירה תבנית של שכפול קוד \"The Mother of All Evil\", אשר מעבירה בנו צמרמורת רק עם הזכרת שמה.

מתי לבחור בפרדיגמה הטרוגנית?

השיקולים העיקריים לפרדיגמה הטרוגנית הם:

  • שימוש במשאבים מיוחדים: חומרה מיוחדת ויקרה שזקוקים לה עבור שירות Y ולא עבור X וכך אפשר לחסוך בעלויות.
    • מקרה נפוץ יותר – צורך בזיכרון רב. לדוגמא: שירות Y משתמש ב in-memory Database וזקוק לכמה עשרות GB של זכרון כדי לפעול בצורה מיטבית. דוגמא נפוצה היא חוות זיכרון נוסח memcached או [terracotta[2.
  • השירות רלווני במיקום גיאוגרפי מסוים / מיקום מסוים ברשת. למשל: השירות מבצע sniffing על הרשת או חייב להיות מותקן במיקום מסוים כדי לגשת לשירותים שהוא זקוק להם. 

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

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

\"זיכרון, מכיוון ששירות Y דורש כ 2GB זכרון נוסף בכדי לרוץ\".
מכיוון שזיכרון הוא זול כ\"כ ועלות פיתוח של High Availability היא גבוהה כ\"כ + ניצול מרבי של חומרה מחזיר מהר מאוד עלות של מעט זיכרון נוסף – טיעון זה לא נראה לי רציני.

הלקוחות שלנו רוצים לקנות שירות לראות את הקופסא שהם קנו.
שמעתי גם את זה. לפי דעתי זהו פידבק של אנשי מכירות או Professional Services ולא באמת לקוחות. לקוחות שאני מכיר מוטרדים מעלות התחזוקה הכוללת (TCO) שמושפעת יותר מ High Availability או אחידות החומרה. כשעבדתי בנייס, הפסדנו עסקאות כי השרת שלנו היה 3U (ר [3]) והשרת של המתחרה היה חלש קצת יותר אבל נכנס ב 2U (כלומר – קצת מקום איכסון היה מספיק משמעותי לעסקה). במידה וטיעון זה עלה – שווה לבקש לשוחח עם כמה לקוחות ולהבין במה מדובר.

\"זיכרון, מכיוון ששירות Y דורש כ 20GB זכרון נוסף כדי לרוץ\"
זהו אכן כלל-האצבע המצביע מתי הפרדיגמה ההטרוגנית עדיפה, אבל לפי דעתי כדאי לחשוב מעט ולא להחליט מייד. כמה עולה 20GB (ר [4]) זיכרון ומה מחיר חוסר-הזמינות?תזכורת: אלא אם מדובר בשרתי Unix עתיקים (שם הזיכרון יקר להחריד) – 20GB זיכרון הם לא דבר מאוד יקר. שווה לעשות את השיקול הכלכלי. לעיתים יהיה שווה לשים שרתים עם זכרון רב ולהשאר עם פרדיגמה הומוגנית (בעיקר ב cluster קטן). לעיתים באמת שווה לעשות את ההפרדה. במערכת עם מספר רב של שרתים (לרוב מערכת on-demand) ניתן לבחור בגישה מעורבת ולהנות מ-2 העולמות. לדוגמא: אם יש לי 12 שרתים אני יכול להקצות 8 לשירות X ו 4 לשירות Y (גישה הטרוגנית), אך כל קבוצה של שרתים תנוהל ב cluster שיספק לי high availability, load balancing וכו\'.

ניהול משאבים הוגן או Resource Consumption Capping
זהו שיקול הגיוני: מספר שירותים במערכת שלנו עלולים לצרוך יותר משאבים ממה שאנו רוצים להקצות להם ולכן אנו רוצים להגביל את את השימוש בהם. גישה אחת לבצע את אכיפת שימוש המשאבים היא פריסה הטרוגנית של שירותים על מחשבים, למשל: יש לי 8 שרתים, 3 יוקצו לשירות X הבעייתי ו 5 לשירות Y. אכיפה כזו היא הקלה ביותר למימוש אך הגמישות לשנות את החלוקה ל 4:4 או 2:6 היא קטנה וייתכן שאותם 3 שרתים של שירות X לא יוקצו בצורה יעילה. פיתרון של Capping בתוכנה הוא פחות מדויק ודורש השקעה נוספת, אך יותר גמיש.
גישה מקובלת אחרת היא ליצור cluster הומוגני בו מספר קטן של שרתים להם רוצים לעשות Capping – מופרד ל cluster לוגי נפרד (כלומר: ה Load Balancer מתבקש לא להעביר להם תעבורה ע\"פ כללים מסוימים). גישה מקובלת עבור ה crawler במערכות SharePoint או Batch Operations במערכות SAP.

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

לסיכום: למרות שהגישה ההומוגנית היא מעט Counter Intuitive – היא טומנת בחובה עוצמה רבה שכדאי לעשות מאמץ ולנצל.

[1] סיפור מעניין בפני עצמו על Scalability.

[2] החבר\'ה מ Terracotta, חברה ישראלית, אוהבים לקרוא לחוות זיכרון אלו NAM – Network Attached Memory, על משקל NAS.

[3] חדרי שרתים בנויים מארונות הנקראים Rack מהם כל slot נספר כ U (אולי קיצור של Unit?). יחידות של 1U הן לרוב ציוד תקשורת כגון Router או Hub בעוד שרתים הם לרוב 2U. שרתים גדולים יותר יתפסו 3U או יותר.

[4] \"איך לעזאזל מגיעים לצריכה של 20GB זיכרון?\" אתם עשויים לתהות? לרוב כשיש Caches גדולים של מספר שירותים או In-Memory-Database.

[5] אפקט איקאה הוא המצב בו אדם שהשקיע עבודה מסויימת במוצר מתאהב בו ורואה תמונה מוטה של הדברים. במקור, האפקט מתואר כך שאדם יאהב יותר את הרהיט הפשוט מאיקאה שהרכיב בעצמו, על פני רהיט איכותי יותר שבהרכבתו לא היה מעורב. הנקודה המפתיעה היא שאדם השקיע חלק מהעבודה (איקאה) יתאהב במוצר בצורה חזקה יותר מזה שבנה את המוצר לבד מ Scratch.