*[English](README.md) ∙ [日本語](README-ja.md) ∙ [简体中文](README-zh-Hans.md) ∙ [繁體中文](README-zh-TW.md) | [العَرَبِيَّة‎](https://github.com/donnemartin/system-design-primer/issues/170) ∙ [বাংলা](https://github.com/donnemartin/system-design-primer/issues/220) ∙ [Português do Brasil](https://github.com/donnemartin/system-design-primer/issues/40) ∙ [Deutsch](https://github.com/donnemartin/system-design-primer/issues/186) ∙ [ελληνικά](https://github.com/donnemartin/system-design-primer/issues/130) ∙ [עברית](https://github.com/donnemartin/system-design-primer/issues/272) ∙ [Italiano](https://github.com/donnemartin/system-design-primer/issues/104) ∙ [한국어](https://github.com/donnemartin/system-design-primer/issues/102) ∙ [فارسی](https://github.com/donnemartin/system-design-primer/issues/110) ∙ [Polski](https://github.com/donnemartin/system-design-primer/issues/68) ∙ [русский язык](https://github.com/donnemartin/system-design-primer/issues/87) ∙ [Español](https://github.com/donnemartin/system-design-primer/issues/136) ∙ [ภาษาไทย](https://github.com/donnemartin/system-design-primer/issues/187) ∙ [Türkçe](https://github.com/donnemartin/system-design-primer/issues/39) ∙ [tiếng Việt](https://github.com/donnemartin/system-design-primer/issues/127) ∙ [Français](https://github.com/donnemartin/system-design-primer/issues/250) | [Add Translation](https://github.com/donnemartin/system-design-primer/issues/28)* **עזרו [לתרגם](TRANSLATIONS.md) את המדריך!** # המדריך לתכנון מערכות (The System Design Primer)


## מוטיבציה
> ללמוד איך לתכנן מערכות ב-scale גדול. > > להתכונן לראיונות ארכיטקטורה. ### ללמוד איך לתכנן מערכות ב-scale גדול ללמוד כיצד לתכנן מערכות סְקֵילָבִּילִיוּת יסייע לך להפוך למהנדס תוכנה טוב יותר. תכנון מערכות הוא נושא רחב. יש **כמות אדירה של משאבים ברחבי הרשת** על עקרונות של תכנון מערכות. ה-repo הזה הוא **אוסף מסודר** של משאבים שנועדו לעזור לך ללמוד איך לבנות מערכות ב-scale. ### ללמוד מקהילת הקוד הפתוח מדובר בפרויקט קוד פתוח (open source) שמתעדכן באופן מתמשך. מוזמנים [לתרום!](#contributing) ### להתכונן לראיונות ארכיטקטורה בנוסף לראיונות קידוד, ארכיטקטורה היא **רכיב נדרש** כחלק מתהליך **ראיונות טכניים** בהרבה חברות טכנולוגיות. **תוכל לתרגל שאלות ארכיטקטורה נפוצות** ואף **להשוות** את התוצאות שלך עם **פתרונות לדוגמה**: דיונים, קוד, ודיאגרמות. ### נושאים נוספים להכנה לראיונות:
## כרטיסיות Anki


החבילות המוכנות של כרטיסיות [Anki](https://apps.ankiweb.net/) משתמשות בשיטת **חזרתיות מבוססת מרווחים (Spaced Repetition)** כדי לעזור לך לזכור מושגים חשובים בתכנון מערכות. מומלצות לשימוש בדרכים. ### משאב לראיונות קידוד: אתגרי קידוד אינטראקטיביים מחפש משאבים שיעזרו לך להתכונן [**לראיונות קידוד**](https://github.com/donnemartin/interactive-coding-challenges)?


תעיף מבט על ה-repo המקביל [**Interactive Coding Challenges**](https://github.com/donnemartin/interactive-coding-challenges), שמכיל חבילת Anki נוספת:
## תרומה למדריך
> ללמוד מהקהילה. אל תהסס להגיש pull requests כדי לעזור: תכנים שעדיין דורשים ליטוש מסומנים בתור תחת פיתוח. מומלץ לעיין בהנחיות לתרומה לפני התחלה.
## אינדקס נושאים בארכיטקטורה
> סיכומים של נושאים שונים בתכנון מערכות, כולל יתרונות וחסרונות. **כל החלטה כוללת פשרות (trade-offs)**. > > כל חלק מכיל קישורים להרחבה וללמידה מעמיקה יותר.


אינדקס נושאים
## מדריך למידה
> נושאים מוצעים ללימוד לפי לוח הזמנים לריאיון שלך (קצר, בינוני, ארוך)


**ש: עבור הראיונות, האם אני אמור לדעת כל מה שכתוב כאן?** **ת: לא, אתה לא צריך לדעת הכול כדי להתכונן לריאיון**. מה שאתה תישאל עליו בריאיון תלוי בדברים כגון: לרוב מצופה ממועמדים מנוסים יותר לדעת יותר על ארכיטקטורה ותכנון מערכות. ארכיטקטים או ראשי צוותים מצופים לדעת יותר מאשר עובדים בודדים. חברות טכנולוגיות מובילות לרוב יערכו ריאיון אחד או יותר של ארכיטקטורה. רצוי להתחיל רחב ולהעמיק במספר תחומים. זה עוזר לדעת קצת בנוגע למספר נושאי מפתח בתכנון מערכות. תתאים את המדריך לפי לוח הזמן שלך, הניסיון, המשרות שאתה מתראיין אליהן, והחברות שבהן אתה מתראיין.
קצר בינוני ארוך
קרא את הנושאים בתכנון מערכות כדי לקבל הבנה כללית של איך מערכות עובדות :+1: :+1: :+1:
קרא כמה מאמרים מתוך בלוגים של חברות שאתה מתראיין אליהן :+1: :+1: :+1:
קרא על כמה ארכיטקטורות מהעולם האמיתי :+1: :+1: :+1:
חזור על איך לגשת לשאלת ריאיון בתכנון מערכות :+1: :+1: :+1:
תרגל שאלות ריאיון בתכנון מערכות עם פתרונות כמה הרבה רוב
תרגל שאלות ריאיון בתכנון מונחה עצמים עם פתרונות כמה הרבה רוב
חזור על שאלות ריאיון נוספות בתכנון מערכות כמה הרבה רוב
## איך לגשת לשאלת ריאיון ארכיטקטורה
> איך לפתור שאלת ראיון ארכיטקטורה. ראיון ארכיטקטורה הוא **שיחה פתוחה**. מצופה ממך להוביל אותה. אתה יכול להיעזר בצעדים הבאים כדי להנחות את הדיון. כדי לחזק את ההבנה של התהליך, תעבור על [שאלות ריאיון בתכנון מערכות עם פתרונות](#system-design-interview-questions-with-solutions) אל מול הצעדים הבאים: ### תאר מקרי שימוש, אילוצים והנחות עבודה אסוף דרישות והגדר את ה-scope של הבעיה. שאל שאלות כדי להבהיר את מקרי השימוש והאילוצים. דון בהנחות העבודה שאתה עושה. ### שלב 2: כתוב תכנון במבט על (high level design) כתוב תכנון high level עם כל הרכיבים החשובים. ### שלב 3: תכנן את הרכיבים המרכזיים צלול לפרטים של כל רכיב מרכזי. לדוגמה, אם התבקשת לתכנן [שירות קיצור כתובות url](solutions/system_design/pastebin/README.md), דון בנושאים הבאים: ### שלב 4: תבצע scale לתכנון זהה וטפל בצווארי בקבוק, בהתאם לאילוצים. למשל, האם תזדקק לאחד מהפתרונות הבאים כדי להתמודד עם בעיות של סקילביליות? דון בפתרונות אפשריים וה-trade-offs. הכול הוא trade-off. התמודד עם צווארי בקבוק בעזרת [עקרונות תכנון מערכת סקילבילית](#index-of-system-design-topics). ### חישובים "על גב המעטפה" (מהירים) ייתכן שיבקשו ממך לבצע הערכות באופן ידני. ראה את [הנספח](#appendix) עבור המשאבים הבאים: * [Use back of the envelope calculations](http://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html) * [Powers of two table](#powers-of-two-table) * [Latency numbers every programmer should know](#latency-numbers-every-programmer-should-know) ### מקורות לקריאה נוספת עיין בקישורים הבאים כדי להבין טוב יותר למה לצפות: * [How to ace a systems design interview](https://www.palantir.com/2011/10/how-to-rock-a-systems-design-interview/) * [The system design interview](http://www.hiredintech.com/system-design) * [Intro to Architecture and Systems Design Interviews](https://www.youtube.com/watch?v=ZgdS0EUmn70) * [System design template](https://leetcode.com/discuss/career/229177/My-System-Design-Template)
## שאלות ריאיון תכנון מערכות עם פתרונות
> שאלות נפוצות בריאיון ארכיטקטורה עם הסברים לדוגמה, קוד, ודיאגרמות. > > הפתרונות מפנים לתוכן שנמצא בתיקיית `solutions/`.
שאלה פתרון
תכנן את pastebin.com (או bit.ly) פתרון
תכנן את ציר הזמן והחיפוש של טוויטר (או הפיד והחיפוש של פייסבוק) פתרון
תכנן web crawler פתרון
תכנן את Mint.com פתרון
תכנן את מבני הנתונים של רשת חברתית פתרון
תכנן אחסון key-value למנוע חיפוש פתרון
תכנן את מנגנון דירוג המכירות לפי קטגוריה של אמזון פתרון
תכנן מערכת שיכולה לגדול למיליוני משתמשים על AWS פתרון
הוסף שאלה לתכנון מערכת תרום
### תכנן את pastebin.com (או bit.ly) [צפה בתרגיל ובפתרון](solutions/system_design/pastebin/README.md)
הצג/הסתר דיאגרמה


### תכנן את ציר הזמן והחיפוש של טוויטר (או הפיד והחיפוש של פייסבוק) [צפה בתרגיל ובפתרון](solutions/system_design/twitter/README.md)
הצג/הסתר דיאגרמה


### תכנן web crawler [צפה בתרגיל ובפתרון](solutions/system_design/web_crawler/README.md)
הצג/הסתר דיאגרמה


### תכנן את Mint.com [צפה בתרגיל ובפתרון](solutions/system_design/mint/README.md)
הצג/הסתר דיאגרמה


### תכנן את מבני הנתונים של רשת חברתית [צפה בתרגיל ובפתרון](solutions/system_design/social_graph/README.md)
הצג/הסתר דיאגרמה


### תכנן אחסון key-value למנוע חיפוש [צפה בתרגיל ובפתרון](solutions/system_design/query_cache/README.md)
הצג/הסתר דיאגרמה


### תכנן את מנגנון דירוג המכירות לפי קטגוריה של אמזון [צפה בתרגיל ובפתרון](solutions/system_design/sales_rank/README.md)
הצג/הסתר דיאגרמה


### תכנן מערכת שיכולה לגדול למיליוני משתמשים על AWS [צפה בתרגיל ובפתרון](solutions/system_design/scaling_aws/README.md)
הצג/הסתר דיאגרמה


## שאלות ריאיון בתכנון מונחה עצמים עם פתרונות
> שאלות נפוצות בתכנון מונחה עצמים עם הסברים לדוגמה, קוד, ודיאגרמות. > > הפתרונות מפנים לתוכן שנמצא בתיקיית `solutions/`. >**הערה: החלק הזה עדיין בפיתוח**
שאלה פתרון
תכנן Hash Map פתרון
תכנן מנגנון Cache בשיטת Least Recently Used פתרון
תכנן מרכז שירות טלפוני (Call Center) פתרון
תכנן חפיסת קלפים פתרון
תכנן חניון פתרון
תכנן שרת צ'אט פתרון
תכנן מערך מעגלי תרום
הוסף שאלה בעיצוב מונחה עצמים תרום
## נושאים בתכנון מערכות: התחל כאן
חדש בתחום תכנון מערכות? ראשית, תצטרך לקבל הבנה בסיסית של העקרונות הנפוצים, ללמוד מה הם, איך משתמשים בהם, מה היתרונות והחסרונות של כל אחד מהם. ### שלב 1: צפה בהרצאה על סקילביליות [Scalability Lecture at Harvard](https://www.youtube.com/watch?v=-W9F__D3oY4) * Topics covered: * Vertical scaling * Horizontal scaling * Caching * Load balancing * Database replication * Database partitioning ### שלב 2: קרא מאמר על סקילביליות [Scalability](https://web.archive.org/web/20221030091841/http://www.lecloud.net/tagged/scalability/chrono) * Topics covered: * [Clones](https://web.archive.org/web/20220530193911/https://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) * [Databases](https://web.archive.org/web/20220602114024/https://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) * [Caches](https://web.archive.org/web/20230126233752/https://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) * [Asynchronism](https://web.archive.org/web/20220926171507/https://www.lecloud.net/post/9699762917/scalability-for-dummies-part-4-asynchronism) ### השלבים הבאים בהמשך, נסתכל על trade-offs ב-high level: * **Performance** vs **scalability** * **Latency** vs **throughput** * **Availability** vs **consistency** נזכור כי **הכול זה trade-off**. לאחר מכן נצלול לנושאים ספציפיים יותר כמו DNS, CDN ו-load balancers.
## ביצועים (Performance) מול סקילביליות (Scalability)
שירות הוא **סקילבילי (scalable)** אם הוא משתפר **בביצועים (performance)** שלו באופן פרופורציונלי למשאבים שנוספו. באופן כללי, שיפור בביצועים פירושו היכולת לתת שירות ליותר יחידות עבודה, אך הוא יכול גם לבוא לידי ביטוי ביכולת להתמודד עם יחידות עבודה גדולות יותר, ככל שהדאטא גדל.1 דרך נוספת להסתכל על ביצועים מול סקילביליות ### מקורות וקריאה נוספת * [A word on scalability](http://www.allthingsdistributed.com/2006/03/a_word_on_scalability.html) * [Scalability, availability, stability, patterns](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/)
## שיהוי (Latency) מול תפוקה (Throughput)
**שיהוי** הוא הזמן שנדרש כדי לבצע פעולה כלשהי או להפיק תוצאה כלשהי **תפוקה** היא מספר הפעולות או התוצאות ליחידת זמן. באופן כללי, כדאי לשאוף **לתפוקה מקסימלית** עם **שיהוי סביר**. ### חומרים וקריאה נוספת * [Understanding latency vs throughput](https://community.cadence.com/cadence_blogs_8/b/fv/posts/understanding-latency-vs-throughput)
## זמינות (Availability) מול עקביות (Consistency)
### משפט CAP


Source: CAP theorem revisited

במערכות מחשוב מבוזרות, ניתן לתמוך רק בשניים מתוך שלושת התנאים הבאים: *ניתן לצאת מנקודת הנחה שרשתות לא אמינות - כך שנהיה חייבים לתמוך ב-״Partition tolerance״. לכן, נצטרך לבחור אחד משני האחרים - זמינות או עקביות.* #### בחירה ב-CP - עקביות ועמידות לפיצול המתנה לתשובה מהמערכת (אשר סובלת מ-network partition) עלולה להסתיים בשגיאת timeout. לכן, CP הוא בחירה טובה במידה ויש הצדקה עסקית לקריאות וכתיבות אטומיות. #### בחירה ב-AP - זמינות ועמידות לפיצול תשובות לבקשות מהמערכת מחזירות את הגרסה הזמינה ביותר של הנתונים הזמינים בשרת הרלוונטי, שאינה בהכרח האחרונה. כתיבה עשויה לקחת זמן מסוים עד שתסתיים, עד אשר התקשורת הבעייתית תיפתר. לכן, AP הוא בחירה טובה במידה ויש הצדקה עסקית לעבוד במצב של [eventual consistency](#eventual-consistency) או במידה והמערכת צריכה להמשיך לשרת למרות שגיאות בלתי-תלויות. ### חומרים וקריאה נוספת * [CAP theorem revisited](http://robertgreiner.com/2014/08/cap-theorem-revisited/) * [A plain english introduction to CAP theorem](http://ksat.me/a-plain-english-introduction-to-cap-theorem) * [CAP FAQ](https://github.com/henryr/cap-faq) * [The CAP theorem](https://www.youtube.com/watch?v=k-Yaq8AHlFA)
## דפוסי עקביות (Consistency Patterns)
כאשר קיימים מספר עותקים של אותם נתונים, עלינו להחליט כיצד לסנכרן ביניהם כדי שלקוחות יקבלו תצוגה עקבית של המידע. ניזכר בהגדרה של עקביות מתוך [משפט CAP](#cap-theorem): כל קריאה מקבלת את הכתיבה העדכנית ביותר או שגיאה. ### עקביות חלשה (Weak Consistency) לאחר כתיבה, קריאות עשויות לראות או לא לראות את הערך החדש שנכתב. הגישה כאן היא של best effort - המאמץ הטוב ביותר. גישה זו נפוצה במערכות כמו memcached. עקביות חלשה מתאימה למקרים של מערכות זמן-אמת, כמו VoIP, שיחות וידאו, ומשחקים מרובי משתתפים. לדוגמה, אם אתה בשיחת טלפון ומאבד קליטה לכמה שניות, כשאתה חוזר אתה לא שומע מה שנאמר בזמן שלא הייתה קליטה. ### עקביות לא מיידית (Eventual Consistency) לאחר כתיבה, הקריאות יראו בסופו של דבר את מה שנכתב (בדרך כלל תוך מספר מילישניות). הנתונים משוכפלים באופן אסינכרוני. גישה זו נפוצה במערכות כמו DNS ומייל. עקביות לא מיידית מתאימה למערכות ששומרות על זמינות גבוהה במיוחד. ### עקביות חזקה (Strong Consistency) לאחר כתיבה, הקריאות יראו תמיד את הערך החדש שנכתב. השכפול מתבצע באופן סינכרוני. גישה זו נפוצה במערכות קבצים ובמסדי נתונים רלציוניים (RDBMS). עקביות חזקה מתאימה למערכות שדורשות טרנזקציות. ### מקורות וקריאה נוספת - [Transactions across data centers](http://snarfed.org/transactions_across_datacenters_io.html)
## דפוסי זמינות (Availability Patterns)
קיימים שני דפוסים משלימים לתמיכה בזמינות גבוהה: **מעבר אוטומטי (fail-over)** ו-**שכפול (replication)**. ### גיבוי בזמן כישלון (Fail-Over) #### אקטיבי-פסיבי (Active-Passive) במבנה אקטיבי-פסיבי, נשלחים heartbeat-ים בין השרת הפעיל לשרת הרזרבי (הפסיבי). אם ה-heartbeat נקטע, השרת הפסיבי לוקח את כתובת ה-IP של הפעיל וממשיך את השירות. משך זמן ההשבתה תלוי אם השרת הפסיבי פועל מראש במצב 'חם' (hot standby), או שיש להפעילו ממצב 'קר' (cold standby). רק השרת הפעיל מקבל תעבורה. סוג זה נקרא גם Master-Slave. #### אקטיבי-אקטיבי (Active-Active) במבנה אקטיבי-אקטיבי, שני השרתים מקבלים תעבורה ומחלקים ביניהם את העומס. אם השרתים חשופים פומבית, שרת ה-DNS צריך לדעת על כתובות ה-IP הציבוריות של שניהם. אם השרתים פנימיים, על לוגיקת האפליקציה להכיר את שניהם. סוג זה נקרא גם Master-Master. ### חסרונות של מעבר אוטומטי ### שכפול (Replication) #### עבור Master-Slave/Master-Master נושא זה נדון בפירוט נוסף בחלק על [מסדי נתונים](#database): - [Master-slave replication](#master-slave-replication) - [Master-master replication](#master-master-replication)
### זמינות במספרים נהוג למדוד זמינות לפי זמן פעילות (uptime) או חוסר פעילות (downtime)כאחוז מהזמן שבו השירות פועל. המדד הנפוץ הוא לפי מספר התשיעיות — לדוגמה: שירות עם זמינות של 99.99% מתואר כבעל ארבע תשיעיות. #### זמינות של 99.9% — שלוש תשיעיות | Duration | Acceptable downtime| |---------------------|--------------------| | Downtime per year | 8h 45min 57s | | Downtime per month | 43m 49.7s | | Downtime per week | 10m 4.8s | | Downtime per day | 1m 26.4s | #### זמינות של 99.99% — ארבע תשיעיות | Duration | Acceptable downtime| |---------------------|--------------------| | Downtime per year | 52min 35.7s | | Downtime per month | 4m 23s | | Downtime per week | 1m 5s | | Downtime per day | 8.6s | #### זמינות במקביל לעומת בטור אם שירות מורכב ממספר רכיבים שעלולים להיכשל, הזמינות הכוללת של השירות תלויה באופן שבו הם מסודרים - בטור או במקביל. ###### בטור כאשר שני רכיבים עם זמינות קטנה מ-100% מסודרים בטור, הזמינות הכוללת יורדת: ``` Availability (Total) = Availability (Foo) * Availability (Bar) ``` אם גם `Foo` וגם `Bar` זמינים ברמה של 99.9%, הזמינות הכוללת שלהם בטור תהיה 99.8%. ###### במקביל הזמינות הכוללת עולה כאשר שני רכיבים בעלי זמינות קטנה מ־100% פועלים במקביל: ``` Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar)) ``` אם גם `Foo` וגם `Bar` זמינים ברמה של 99.9%, הזמינות הכוללת שלהם במקביל תהיה 99.9999%. ## מערכת שמות דומיינים (DNS)


מקור: מצגת אבטחת DNS

מערכת שמות דומיינים (DNS) ממירה שם דומיין כמו `www.example.com` לכתובת IP. ה-DNS בנוי בהיררכיה: כאשר ישנם כמה שרתי ניהול בשכבה העליונה. ה-router שלך או ספק האינטרנט (ISP) מספקים כתובות לשרת(י) DNS שיש לפנות אליהם בעת ביצוע חיפוש של כתובת. שרתי DNS בשכבה נמוכה יותר, מבצעים cache למיפויים, שעלולים להיות לא עדכניים (stale) אם הרשומה המעודכנת עוד לא עברה מהשרת בשכבה הגבוהה עד למטה (propagation delays). המיפוי של ה-DNS יכול להישמר על ידי הדפדפן או מערכת ההפעלה לפרק זמן מסוים, הנקבע על ידי [TTL – Time To Live](https://he.wikipedia.org/wiki/Time_to_live). שירותים מנוהלים כמו [CloudFlare](https://www.cloudflare.com/dns/) ו-[Route 53](https://aws.amazon.com/route53/) מספקים DNS מנוהל. חלקם מאפשרים ניתוב תעבורה בשיטות שונות: - [Weighted round robin](https://www.jscape.com/blog/load-balancing-algorithms) - Prevent traffic from going to servers under maintenance - Balance between varying cluster sizes - A/B testing - [Latency-based](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-latency.html) - [Geolocation-based](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-geo.html) ### חסרונות (DNS) ### מקורות וקריאה נוספת - [DNS architecture](https://technet.microsoft.com/en-us/library/dd197427(v=ws.10).aspx) - [Wikipedia](https://en.wikipedia.org/wiki/Domain_Name_System) - [DNS articles](https://support.dnsimple.com/categories/dns/)
## רשתות הפצת תוכן (CDN)


מקור: Why use a CDN

רשת הפצת תוכן (CDN) היא רשת גלובלית ומבוזרת של שרתי proxy, אשר מנגישים תכנים ממיקומים הקרובים יותר למשתמש הקצה. בדרך כלל, קבצים סטטיים כמו HTML/CSS/JS, תמונות וסרטונים, מונגשים על ידי CDN, למרות שיש כאלו כמו CloudFront של Amazon התומכים גם בתכנים דינמיים. מיפוי ה-DNS שיתקבל ינחה את הלקוחות לאיזה שרת להתחבר. הגשת תוכן מ-CDN משפר ביצועים משמעותית בשני אופנים: ### דחיפה (Push) ב-Push CDN התוכן נדחף אל ה-CDN בכל פעם שהוא משתנה בשרת המקור. האחריות על העלאת הקבצים וכתיבת ה-URLs המופנים ל-CDN היא שלך. אתה מגדיר את הזמן שבו פג תוקפו של תוכן מסוים, ומתי הוא מתעדכן. תוכן מועלה רק כאשר הוא חדש, או עבר שינוי, מה שמפחית תעבורה אבל ממקסם על האחסון. אתרים עם מעט תוכן או תעבורה, או עם תוכן שלא מתעדכן באופן תדיר עובדים טוב עם Push CDN. התוכן נמצא ב-CDN פעם אחת, במקום שישלפו אותו מחדש בתדירות קבועה. ### משיכה (Pull) ב-Pull CDN התוכן נשלף מהשרת המקור רק כאשר משתמש מבקש אותו לראשונה. הקבצים נשארים בשרת שלך ו-URLs מפנים ל-CDN. הבקשה הראשונית איטית יותר עד שהקובץ נשמר ב-CDN. משך הזמן שבו ישאר ה-cache נקבע על-ידי [TTL – Time to Live](https://he.wikipedia.org/wiki/Time_to_live). ה-Pull CDN חוסך שטח אחסון על ה-CDN, אך עלול ליצור תעבורה מיותרת אם קבצים פגי-תוקף נשלפים שוב לפני ששונו בפועל. Pull CDN מתאים לאתרים עתירי תעבורה, שכן העומס מתפזר וה-CDN שומר רק קבצים שנדרשו לאחרונה. ### חסרונות (CDN) ### מקורות וקריאה נוספת - [Globally distributed content delivery](https://figshare.com/articles/Globally_distributed_content_delivery/6605972) - [The differences between push and pull CDNs](http://www.travelblogadvice.com/technical/the-differences-between-push-and-pull-cdns/) - [Wikipedia](https://en.wikipedia.org/wiki/Content_delivery_network)
## מאזן עומסים (Load Balancer)


Source: Scalable system design patterns

מאזן עומסים מבזר בקשות נכנסות מלקוח בין משאבי חישוב שונים כגון שרתי אפליקציה ומסדי נתונים. עבור כל בקשה, הוא מחזיר את התשובה ממשאב החישוב המתאים, אל הלקוח המתאים. מאזן עומסים יעיל ב: מאזן עומסים ניתן למימוש כחומרה (יקר) או כתוכנה כדוגמת HAProxy. יתרונות נוספים: כדי להגן מפני כישלונות נהוג להקים מספר מאזני עומסים, במצב [Active-Passive](#אקטיבי-פסיבי-active-passive) או [Active-Active](#אקטיבי-אקטיבי-active-active). מאזן עומסים יכול לנתב את התעבורה על פי מדדים שונים: - Random - Least loaded - Session/cookies - [Round robin or weighted round robin](https://www.g33kinfo.com/info/round-robin-vs-weighted-round-robin-lb) - [Layer 4](#layer-4-load-balancing) - [Layer 7](#layer-7-load-balancing) ### איזון עומסים בשכבה 4 מאזני עומסים בשכבה 4 בוחנים מידע בשכבת התעבורה ([transport layer](#communication)) כדי להחליט כיצד להפיץ בקשות. בדרך כלל, מדובר בכתובות ה-IP של המקור והיעד ובפורטים שבכותרת (header), ולא בתוכן הפקטה (packet). מאזני עומסים בשכבה 4 מעבירים את חבילות הרשת אל ומן השרת הנבחר (upstream server) תוך ביצוע [תרגום כתובות רשת (NAT)](https://www.nginx.com/resources/glossary/layer-4-load-balancing/). ### איזון עומסים בשכבה 7 מאזני עומסים בשכבה 7 בוחנים את [שכבת האפליקציה](#communication) כדי להחליט כיצד להפיץ בקשות. ההחלטה יכולה להתבסס על תוכן הכותרות (headers), גוף ההודעה, ועוגיות (cookies). מאזן עומסים בשכבה 7 מסיים (terminates) את תעבורת הרשת אל מול הלקוח, קורא את ההודעה, מקבל החלטת איזון-עומסים, ואז פותח חיבור לשרת שנבחר. למשל, מאזן כזה יכול לשלוח תעבורת וידאו לשרתים שמאחסנים קטעי וידאו, ובמקביל לנתב תעבורת חיוב משתמשים (billing) לשרתים מוקשחים אבטחתית. לעומת זאת, איזון עומסים בשכבה 4 דורש פחות זמן ומשאבי מחשוב מאשר שכבה 7, אם כי על חומרה מודרנית ההשפעה הביצועית עשויה להיות מזערית. ### גדילה אופקית (Horizontal Scaling) מאזני עומסים מסייעים גם בגדילה אופקית (Horizontal Scaling), וכך משפרים ביצועים וזמינות. הרחבת המערכת באמצעות שרתים זולים חסכונית יותר ומביאה לרמת זמינות גבוהה לעומת **הגדלה אנכית (Vertical Scaling)** – חיזוק שרת יחיד בחומרה יקרה. בנוסף, קל יותר לגייס אנשי מקצוע המיומנים בעבודה עם שרתים סטנדרטיים מאשר כאלה המתמחים במערכות ארגוניות ייעודיות ויקרות. #### חסרונות: גדילה אופקית ### חסרונות: מאזן עומסים ### מקורות וקריאה נוספת - [NGINX architecture](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) - [HAProxy architecture guide](http://www.haproxy.org/download/1.2/doc/architecture.txt) - [Scalability](https://web.archive.org/web/20220530193911/https://www.lecloud.net/post/7295452622/scalability-for-dummies-part-1-clones) - [Wikipedia](https://en.wikipedia.org/wiki/Load_balancing_(computing)) - [Layer 4 load balancing](https://www.nginx.com/resources/glossary/layer-4-load-balancing/) - [Layer 7 load balancing](https://www.nginx.com/resources/glossary/layer-7-load-balancing/) - [ELB listener config](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config.html)
## פרוקסי הפוך (Reverse Proxy)
פרוקסי הפוך הוא שרת אינטרנט המרכז שירותים פנימיים ומספק ממשק אחיד החוצה. בקשות שמגיעות מלקוחות מועברות לשרת ה-backend המסוגל לטפל בהן, ולאחר מכן הפרוקסי מחזיר ללקוח את תגובת השרת. יתרונות הכלולים בצורה זו: ### מאזן עומסים לעומת פרוקסי הפוך ### חסרונות: פרוקסי הפוך ### מקורות וקריאה נוספת - [Reverse proxy vs load balancer](https://www.nginx.com/resources/glossary/reverse-proxy-vs-load-balancer/) - [NGINX architecture](https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/) - [HAProxy architecture guide](http://www.haproxy.org/download/1.2/doc/architecture.txt) - [Wikipedia](https://en.wikipedia.org/wiki/Reverse_proxy)
## שכבת האפליקציה
הפרדת שכבת הרשת משכבת האפליקציה (ידועה גם כשכבת ה-platform), מאפשרת לבצע scaling ולקנפג את שתי השכבות באופן בלתי תלוי. הוספת API חדש גוררת הוספתי שרתי אפליקציה, מבלי להוסיף בהכרח גם שרתי המטפלים בלוגיקת הרשת. עקרון האחריות היחידה (**single respoinsibility principle**) מעודד סרביסים עצמאיים וקטנים שעובדים יחד. צוותים קטנים המטפלים שירותים קטנים יכלוים להתכוונן בצורה מיטבית לגדילה מהירה. Workers בשכבת האפליקציה מסייעים גם [לא-סינכרוניות](#asynchronism). ### מיקרו-סרביסים (Microservices) במונח [Microservices](https://he.wikipedia.org/wiki/מיקרו-שירותים) הכוונה למערך של שירותים קטנים, מודולריים, הניתנים לפריסה עצמאית. כל שירות רץ כתהליך נפרד ומתקשר באמצעות מנגנון פשוט ומוגדר היטב כדי להשיג יעד עסקי.1 לדוגמה, ב-Pinterest יכולים להיות המיקרו-סרביסים הבאים: פרופיל משתמש, עוקבים, פיד, חיפוש, העלאת תמונה וכו'. ### גילוי סרביסים (Service Discovery) מערכות כמו [Consul](https://www.consul.io/docs/index.html), [Etcd](https://coreos.com/etcddocs/latest), ו-[Zookeeper](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) מסייעות לשירותים “למצוא” זה את זה על ידי ניהול ומעקב אחר שמות הסרביסים, כתובות IP, ופורטים. בדיקות דופק ([Health checks](https://www.consul.io/intro/getting-started/checks.html)) — מאמתות את תקינות השירות, לעיתים קרובות באמצעות endpoint HTTP. גם Consul וגם Etcd כוללים [אחסון key-value](#key-value-store) מובנה, השימושי לאחסון קונפיגורציה ונתונים משותפים. ### חסרונות: שכבת האפליקציה ### מקורות וקריאה נוספת - [Intro to architecting systems for scale](http://lethain.com/introduction-to-architecting-systems-for-scale) - [Crack the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) - [Service oriented architecture](https://en.wikipedia.org/wiki/Service-oriented_architecture) - [Introduction to Zookeeper](http://www.slideshare.net/sauravhaloi/introduction-to-apache-zookeeper) - [Here's what you need to know about building microservices](https://cloudncode.wordpress.com/2016/07/22/msa-getting-started/)
## מסדי נתונים (DB)


Source: Scaling up to your first 10 million users

### מסדי נתונים רלציוניים (RDBMS) מסד נתונים רלציוני כמו SQL הוא אוסף פריטי מידע המאורגנים בטבלאות. **ACID** הוא סט מאפיינים של [טרנזקציות](https://he.wikipedia.org/wiki/טרנזקציה_(בסיס_נתונים)) במסדי נתונים רלציוניים: ישנן טכניקות רבות להגדלת (scaling) מסד נתונים רלציוני: שכפול Master-Slave, שכפול Master-Master, פדרציה (Federation), חלוקה (Sharding), דה-נורמליזציה (Denormalization), ו-SQL Tuning. --- #### שכפול Master-Slave ה-master משרת קריאות וכתיבות (RW), ומשכפל את הכתיבות ל-slave אחד או יותר שמשרת רק קריאות (R). ה-slaves יכול לשכפל את הדאטא ל-slaves נוספים במבנה של מעין עץ. אם ה-master נופל, המערכת יכולה להמשיך לרוץ במצב read-only עד שאחד ה-slaves מקודם להיות master, או שמקצים master חדש.


Source: Scalability, availability, stability, patterns

##### חסרונות: Master-Slave --- #### שכפול Master-Master שני ה-masters משרתים קריאה וכתיבה (RW) ומתאמים אחד עם השני את הכתיבות. אם אחד מהם נופל, המערכת יכולה להמשיך לתפקד במצב של קריאה וכתיבה.


Source: Scalability, availability, stability, patterns

##### חסרונות: Master-Master ##### חסרונות: Replication (כללי) ##### מקורות וקריאה נוספת: Replication - [Scalability, availability, stability, patterns](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) - [Multi-master replication](https://en.wikipedia.org/wiki/Multi-master_replication) --- #### פדרציה (Federation)


Source: Scaling up to your first 10 million users

בפדרציה (או חלוקה פונקציונלית) מפצלת DB לפי הפונקציות שלו. לדוגמה, במקום DB מונוליטי בודד, ניתן לנהל 3 DBים נפרדים: **פורומים, משתמשים, ומוצרים**, מה שגורר פחות תעבורת קריאה וכתיבה לכל DB, ועקב כך פחות replication lag. מסדי נתונים קטנים יותר מאפשרים יותר דאטא שנכנס בזיכרון, שיכול להוביל ליותר cache hits מוצלחים. בלי master אחד מרכזי שאחראי לדאוג לכל הכתיבות באופן סדרתי, אפשר לכתוב במקביל ל-DB שונים עבור כל סוג של נתונים, ובכך להגדיל את ה-throughput. ##### חסרונות: פדרציה ##### מקורות וקריאה נוספת: פדרציה - [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=kKjm4ehYiMs) --- #### חלוקה (Sharding)


Source: Scalability, availability, stability, patterns

חלוקה מפזרת את הדאטא בין DBים שונים כך שכל DB מנהל חלק (subset) מסוים של הדאטא. נסתכל למשל על DB של משתמשים, ככל שכמות המשתמשים עולה, יותר חלקים (shards) מתווספים ל-cluster. בדומה ליתרונות של [פדרציה](), חלוקה גוררת פחות תעבורה של קריאות וכתיבות, פחות שכפול, ויותר cache hits. גודל ה-index גם קטן, מה שלרוב משפר את קצב ביצוע השאילתות. אם shard אחד נופל, כל שאר ה-shards עדיין פעילים, למרות שנרצה לבצע שכפול מסוים כדי להימנע מאיבוד מידע. כמו פדרציה, אין master מרכזי אחיד שכל הכתיבות עוברות דרכו, מה שמאפשר לכתוב במקביל ל-DBים שונים ולהגביר את ה-throughput. דרכים נפוצות לבצע sharding לטבלה של משתמשים הן באמצעות האות הראשונה של שם המשפחה, או המיקום הגיאוגרפי של המשתמש. ##### חסרונות: Sharding ###### מקורות וקריאה נוספת - [The coming of the shard](http://highscalability.com/blog/2009/8/6/an-unorthodox-approach-to-database-design-the-coming-of-the.html) - [Shard database architecture](https://en.wikipedia.org/wiki/Shard_(database_architecture)) - [Consistent hashing](http://www.paperplanes.de/2011/12/9/the-magic-of-consistent-hashing.html) --- #### דנורמליזציה (Denormalization) דנורמליזציה שואפת לשפר ביצועים של קריאות על חשבון חלק מהביצועים של הכתיבות. עותקים מיותרים (משוכפלים באופן מכוון, Redundant) של הדאטא נכתבים במספר טבלאות שונות כדי להימנע מביצוע JOINים יקרים. חלק מה-RDBMSים כמו [PostgreSQL](https://en.wikipedia.org/wiki/PostgreSQL) ו-Oracle תומכים ב-[materialized views](https://en.wikipedia.org/wiki/Materialized_view) אשר דואגים לשמירה של מידע מיותר ושמירת עותקים מיותרים עקביים. כאשר הדאטא מבוזר באמצעות טכניקות כמו [פדרציה]() או [חלוקה](), ניהול JOINים בין ריכוזי מידע שונים מגדיר את המורכבות. דנורמליזציה יכולה לייתר את הצורך לבצע JOINים מורכבים. ברוב המערכות, כמות הקריאות גדולה בהרבה מכמות הכתיבות, ביחס של 100:1 ואף 1000:1. קריה יכולה להוביל לביצוע JOIN מורכב ויקר, מה שעולה בביצוע פעולות דיסק זמן רב. ##### חסרונות: דנורמליזציה ###### מקורות וקריאה נוספת - [Denormalization](https://en.wikipedia.org/wiki/Denormalization) --- #### SQL Tuning התחום של SQL Tuning הוא רחב, ונכתבו עליו לא מעט [ספרים](https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=sql+tuning). חשוב לבצע **Benchmark** ו-**Profile** כדי לדמות עומסים ולגלות צווארי-בקבוק. התוצאות של השימוש בכלים אלו עשויה להוביל לאופטימיזציות הבאות: ##### הידוק הסכימה (Tighten up the schema) ##### השתמש באינדקסים טובים (Use good indices) ##### מניעת JOIN יקר ##### חלוקה לטבלאות (Partitioning) ##### כוונון Query Cache ##### מקורות וקריאה נוספת - [Tips for optimizing MySQL queries](http://aiddroid.com/10-tips-optimizing-mysql-queries-dont-suck/) - [Is there a good reason i see VARCHAR(255) used so often?](http://stackoverflow.com/questions/1217466/is-there-a-good-reason-i-see-varchar255-used-so-often-as-opposed-to-another-l) - [How do null values affect performance?](http://stackoverflow.com/questions/1017239/how-do-null-values-affect-performance-in-a-database-search) - [Slow query log](http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html) ### NoSQL לעומת SQL קלאסי, NoSQL הוא אוסף של מבני נתונים הנשמרים בתור **Key-Value Store**, **Document Store**, **Wide Column Store** או **Graph Database**. הנתונים מנורמלים פחות, ופעולות JOIN מבוצעות לרוב בקוד האפליקציה עצמה. רוב האחסונים מסוג NoSQL אינם תומכים בטרנזקציות ACID מלאות ומספקים [עקביות לא מיידית](#eventual-consistency). מקובל לסמן את מאפייני NoSQL בראשי התיבות **BASE** (תווך שימוש ב[משפט CAP](#cap-theorem), תכונות BASE מתעדפות זמינות (A) על פני עקביות (C)): מעבר לבחירה בין [SQL ל-NoSQL](#sql-or-nosql), חשוב להבין איזה סוג NoSQL מתאים ביותר לשימוש שלך. נדון בסוגים **Key-Value Stores**, **Document Stores**, **Wide Column Stores** ו-**Graph Databases**. --- #### אחסון Key-Value > הפשטה: Hash Table אחסון Key-Value לרוב מאפשר קריאות וכתיבות ב-O(1) ומגובה באמצעות זיכרון או SSD. ניתן לשמור מפתחות ב[סדר לקסיקוגרפי](), מה שמאפשר שליפה יעילה של טווחי המפתחות. אחסון זה מאפשר תמיכה ב-metadadta עם ערכים. אחסון זה מספק ביצועים גבוהים ולרוב בשימוש עבור מודלי דאטא פשוטים או לדאטא שמשתנה במהירות, כמו שכבת cache in-memory. כיוון שסוגי אחסון זה מציעים סט מצומצם של פעולות, המורכבות נמצאת בשכבת האפלקציה אם נדרשות פעולות נוספות. אחסון זה הוא הבסיס למערכות מורכבות יותר כמו document store ובמקרים מסוימים גם graph db. ##### מקורות וקריאה נוספת: אחסון Key-Value - [Key-value database](https://en.wikipedia.org/wiki/Key-value_database) - [Disadvantages of key-value stores](http://stackoverflow.com/questions/4056093/what-are-the-disadvantages-of-using-a-key-value-table-over-nullable-columns-or) - [Redis architecture](http://qnimate.com/overview-of-redis-architecture/) - [Memcached architecture](https://adayinthelifeof.nl/2011/02/06/memcache-internals/) --- #### אחסון Document > הפשטה: אחסון Key-Value שבו הערך הוא מסמך אחסון Document מתרכז סביב מסמכים (XML, JSON, binary, etc.) כאשר מסמך שומר את כל המידע שקשור לאובייקט מסוים. אחסון זה מספק API או query language כדי לתשאל על בסיס המבנה הפנימי של המסמך עצמו. נשים לב, כי הרבה אחסונים מסוג Key-Value כוללים פיצ'רים כדי לעבוד עם ה-metadata של ה-value, מה שמטשטש את הגבול בין שני סוגי אחסון אלו. על בסיס המימוש הספציפי מאחורי הקלעים, מסמכים מאורגנים לפי אוספים, תגים, metadata או תיקיות. למרות שמסמכים יכולים להיות מאורגנים או מקובצים יחדיו, יכולים להיות להם שדות שונים לחלוטין אחד מהשני. אחסונים כמו [MongoDB](https://www.mongodb.com/mongodb-architecture) ו-[CouchDB](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) מציעים שפה דמוית SQL על מנת לבצע שאילתות מורכבות. [DynamoDB](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/decandia07dynamo.pdf) תומך גם ב-Key-Value וגם במסמכים. אחסונים אלו מספקים גמישות גבוהה ולרוב בשימוש עבור דאטא שמשתנה בתדירות גבוהה. ##### מקורות וקריאה נוספת: אחסון Document - [Document-oriented database](https://en.wikipedia.org/wiki/Document-oriented_database) - [MongoDB architecture](https://www.mongodb.com/mongodb-architecture) - [CouchDB architecture](https://blog.couchdb.org/2016/08/01/couchdb-2-0-architecture/) - [Elasticsearch architecture](https://www.elastic.co/blog/found-elasticsearch-from-the-bottom-up) --- #### אחסון Wide Column


Source: SQL & NoSQL, a brief history

> הפשטה: Map מקונן מסוג > ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>> אחסון Wide Column עובד עם יחידת דאטא בסיסית שהיא עמודה (זוג שם/ערך). עמודות מקובצות תחת column families (כמו טבלת SQL). Super column families הן אוסף של column families. אפשר לגשת לכל עמודה בנפרד עם row key, כאשר עמודות בעלות אותו row key יוצרות שורה. כל ערך מכיל timestamp עבור גרסאות ופתרון קונפליקטים. דוגמאות: Google הציגה את [Bigtable](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) כאחסון הראשון מסוג זה. זה השפיע על פרויקט הקוד הפתוח [HBase](https://www.edureka.co/blog/hbase-architecture/) (באקוסיסטם Hadoop) ו-[Cassandra](http://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archIntro.html) של Facebook. מערכות כמו Bigtable, HBase ו-Cassandra שומרות מפתחות בסדר **לקסיקוגרפי**, וכך מאפשרות שליפת טווחי מפתחות ביעילות. אחסונים אלו מציעים זמינות גבוהה, וסקילביליות גבוהה. לרוב משתמשים בהם לאחסון דאטאסטים מאוד גדולים. ##### מקורות וקריאה נוספת: אחסון Wide Column - [SQL & NoSQL, a brief history](http://blog.grio.com/2015/11/sql-nosql-a-brief-history.html) - [Bigtable architecture](http://www.read.seas.harvard.edu/~kohler/class/cs239-w08/chang06bigtable.pdf) - [HBase architecture](https://www.edureka.co/blog/hbase-architecture/) - [Cassandra architecture](http://docs.datastax.com/en/cassandra/3.0/cassandra/architecture/archIntro.html) --- #### אחסון Graph


Source: Graph database

> הפשטה: גרף ב-DB גרפי כל **צומת** (Node) הוא רשומה, וכל **קשת** (Arc/Edge) היא קשר בין שני צמתים. ה-DB מותאם לייצוג קשרים מורכבים – עם הרבה מפתחות זרים (Foreign Keys) או יחסי Many-to-Many. אחסון זה מאפשר ביצועים גבוהים למודלים עם יחסים מורכבים, למשל כמו רשת חברתית. הטכנולוגיה הזו יחסית חדשה ופות נפוצה; ייתכן קושי למצוא כלי פיתוח ומשאבים. הרבה אחסונים מסוג זה נגישים רק באמצעות [REST APIs](#representational-state-transfer-rest). ##### מקורות וקריאה נוספת: Graph - [Graph database](https://en.wikipedia.org/wiki/Graph_database) - [Neo4j](https://neo4j.com/) - [FlockDB](https://blog.twitter.com/2010/introducing-flockdb) #### מקורות וקריאה נוספת: NoSQL - [Explanation of base terminology](http://stackoverflow.com/questions/3342497/explanation-of-base-terminology) - [NoSQL databases a survey and decision guidance](https://medium.com/baqend-blog/nosql-databases-a-survey-and-decision-guidance-ea7823a822d#.wskogqenq) - [Scalability](https://web.archive.org/web/20220602114024/https://www.lecloud.net/post/7994751381/scalability-for-dummies-part-2-database) - [Introduction to NoSQL](https://www.youtube.com/watch?v=qI_g07C_Q5I) - [NoSQL patterns](http://horicky.blogspot.com/2009/11/nosql-patterns.html) ### SQL or NoSQL


Source: Transitioning from RDBMS to NoSQL

-סיבות לשימוש ב**SQL**: סיבות לשימוש ב-**NoSQL**: דאטא לדוגמה שמתאים מאוד עבור **NoSQL**: - Rapid ingest of clickstream and log data - Leaderboard or scoring data - Temporary data, such as a shopping cart - Frequently accessed ('hot') tables - Metadata/lookup tables ##### מקורות וקריאה נוספת: SQL or NoSQL - [Scaling up to your first 10 million users](https://www.youtube.com/watch?v=kKjm4ehYiMs) - [SQL vs NoSQL differences](https://www.sitepoint.com/sql-vs-nosql-differences/)
## מטמון (Cache)


Source: Scalable system design patterns

שמירת נתונים ב-cache משפרת את זמן טעינת הדפים, ומפחיתה את העומס על השרתים ועל ה-DBים. במודל זה, השרת מחפש האם הבקשה שהגיעה כבר נעשתה בעבר, ומנסה למצוא תוצאה מוכנה, כדי לחסוך את זמן העיבוד על אותה ההודעה מחדש. מסדי נתונים לרוב מרוויחים מהתפלגות אחידה של קריאות וכתיבה על פני החלוקות שלהם (partitions). פריטים שניגשים אליהם הרבה יכולים ליצור זינוק בקריאות וכתיבה לחלוקה מסוימת וליצור צווארי-בקבוק. כאשר שמים שכבת cache לפני ה-DB, פיקים קיצוניים בתעבורה נספגים בזיכרון המהיר של המטמון ולא מעמיסים על ה-DB. ### מטמון בצד לקוח מטמון יכול להיות ממוקם בצד הלקוח (מערכת ההפעלה או הדפדפן), [צד השרת](#reverse-proxy-web-server), או בשכבה נפרדת. ### מטמון CDN ניתן להסתכל על [CDN](#content-delivery-network) גם בתור שכבה של מטמון. ### מטמון בשרת [פרוקסי הפוך](#reverse-proxy-web-server) ומנגנוני cache כמו [Varnish](https://www.varnish-cache.org/) יכולים להנגיש תוכן סטטי ודינמי ישירות. שרתי web יכולים גם לבצע cache לבקשות כדי להחזיר תשובות בלי צורך להגיע עד לשרתי האפליקציה. ### מטמון במסד נתונים ה-DB לרוב כולל רמה מסוימת של caching באופן דיפולטי, אשר מאופטמת למקרה הכללי. ביצוע כיוונון להגדרות האלה עבור תבניות שימוש ספציפיות יכול להאיץ את הביצועים. ### מטמון באפליקציה מטמון in-memory כמו Memcached ו-Redis מהווים אחסון key-value בין האפליקציה ובין ה-DB. כיוון שהדאטא מוחזק ב-RAM, זה הרבה יותר מהיר מ-DB טיפוסי שם הדאטא נשמר על הדיסק. ה-RAM יותר מוגבל מהדיסק, לכן אלגוריתמים של [cache invalidation](https://en.wikipedia.org/wiki/Cache_algorithms) כמו [least recently used (LRU)](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)) עוזרים "לזרוק" את הפריטים שלא נגעו בהן זמן רב (cold) ולהשאיר את הנתונים הרלוונטיים (hot). ל-Redis יש את הפיצ'רים הבאים: יש הרבה רמות שניתן לבצע בהן cache, והן מתחלקות לשתי קטגוריות עיקריות: **database queries** ו-**objects**: - Row level - Query-level - Fully-formed serializable objects - Fully-rendered HTML באופן כללי, עדיף להימנע מביצוע caching לקבצים, דבר המקשה על cloning - שכפול, ועל auto-scaling - הוספה או הורדה של מכונות. ### מטמון ברמת שאילתה בכל פעם שמבצעים שאילתה ל-DB, נעשה hash על השאילתה בתור key, ונאחסן את התוצאה שלה ל-cache. הגישה הזאת סובלת מבעיות של תוקף: ### מטמון ברמת אובייקט במקום לשמור תוצאה של שאילתה, נחשוב על הנתונים כמו על "אובייקט" בקוד. האפליקציה שולפת את המידע מה-DB ומרכיבה ממנו מופע שמתאר אותו תוך שימוש ב-class כלשהו: הצעות לדברים שכדאי לבצע להם cache: - User sessions - Fully rendered web pages - Activity streams - User graph data ### מתי לעדכן את ה-cache? כיוון שאפשר לאחסן רק כמות מוגבלת של מידע ב-cache, יש לבחור באסטרטגיית עדכון ופינוי המקום ב-cache שמתאימה ביותר עבור המערכת. #### אסטרטגיית Cache-Aside


Source: From cache to in-memory data grid

האפליקציה אחראית לבצע קריאה וכתיבה מול האחסון. ה-cache לא מדבר עם האחסון ישירות. האפליקציה עושה את הדברים הבאים: ```python def get_user(self, user_id): user = cache.get("user.{0}", user_id) if user is None: user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id) if user is not None: key = "user.{0}".format(user_id) cache.set(key, json.dumps(user)) return user ``` למשל [Memcached](https://memcached.org/) יכול להיות בשימוש בקטע קוד מהסוג הזה, האפליקציה היא זו שקובעת מתי לקרוא ולכתוב ל-cache. אחרי שהפריט נכתב ל-cache, כל קריאה חוזרת אליו מהירה במיוחד. אסטרטגייה זו נקראת גם lazy loading. רק מידע שנעשתה אליו גישה נכנס ל-cache, מה שמונע שמירה של הרבה דאטא שאין בו שימוש. ##### חסרונות: cache-aside #### אסטרטגיית Write-Through


Source: Scalability, availability, stability, patterns

האפליקציה מתייחסת אל ה-cache כאחסון המרכזי, מבצעת קריאות וכתיבות מולו, כאשר ה-cache אחרי לבצע את הקריאות והכתיבות מול ה-DB: Application code: ```python set_user(12345, {"foo":"bar"}) ``` Cache code: ```python def set_user(user_id, values): user = db.query("UPDATE Users WHERE id = {0}", user_id, values) cache.set(user_id, user) ``` אסטרטגיה זו איטית יותר בשל ביצוע ה-write (שתי כתיבות במקום אחת), אבל קריאות שיקרו בהמשך של הדאטא שזה עתה נכתב יהיו מהירות. המשתמשים לרוב יותר סבלניים לגבי שיהוי כאשר מעדכנים את הדאטא לעומת קריאה שלו. הדאטא ב-cache תמיד עדכני. ##### חסרונות: write through #### אסטרטגיית Write-Behind/Back


Source: Scalability, availability, stability, patterns

האפליקציה מבצעת את הפעולות הבאות: ##### חסרונות: write-behind #### אסטרטגיית Refresh-Ahead


Source: From cache to in-memory data grid

אפשר לקנפג את ה-cache כך שהוא ירענן כל פריט שניגשו אליו לאחרונה לפני שתפוג תקופת ה-TTL שלו (יבצע fetch מול ה-DB). אם המערכת יודעת לחזות בצורה טובה אילו פריטים יבוקשו שוב בקרוב, נקבל latency נמוך יותר משיטות read-through רגילות: המשתמש יקבל תשובה מ-cache שכבר עבר עדכון ברקע (ואין cache miss). ##### חסרונות: refresh-ahead ### חסרונות: cache ### מקורות וקריאה נוספת - [From cache to in-memory data grid](http://www.slideshare.net/tmatyashovsky/from-cache-to-in-memory-data-grid-introduction-to-hazelcast) - [Scalable system design patterns](http://horicky.blogspot.com/2010/10/scalable-system-design-patterns.html) - [Introduction to architecting systems for scale](http://lethain.com/introduction-to-architecting-systems-for-scale/) - [Scalability, availability, stability, patterns](http://www.slideshare.net/jboner/scalability-availability-stability-patterns/) - [Scalability](https://web.archive.org/web/20230126233752/https://www.lecloud.net/post/9246290032/scalability-for-dummies-part-3-cache) - [AWS ElastiCache strategies](http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/Strategies.html) - [Wikipedia](https://en.wikipedia.org/wiki/Cache_(computing))
## אסינכרוניות (Asynchronism)


Source: Intro to architecting systems for scale

ביצוע פעולות באופן אסינכרוני עוזר לקצר זמני תגובה לבקשות עצמן. פעולות כבדות אינן מבוצעות ישירות אלא מתווספות לתור משימות, כאשר התשובה חוזר כמעט מיד. ברקע, המשימה מתבצעת מאוחר יותר. משימות שלוקחות זמן רב יכולות להתבצע מבעוד מועד, כמו aggregation תקופתי של דאטא. הנתונים כבר מוכנים מראש והשליפה תהיה מהירה. ### תורי הודעות (Message Queues) תורי הודעות מקבלים, מחזיקים, ושולחים הודעות. אם פעולה איטית מידי לביצוע באופן סינכרוני, אפשר להשתמש בתור הודעות באופן הבא: המשתמש לא נתקע (blocked) והעבודה מתבצעת ברקע. בזמן הזה, המשתמש יכול לבצע פעולות כדי לגרום לכך להיראות כאילו הפעולה בוצעה. למשל, אם מדובר על העלאה של ציוץ (tweet), הוא יכול להתרפסם מיידית ב-timeline של המשתמש, אבל יקח זמן עד שהוא באמת יישלח לכל העוקבים (ייתכן פער של כמה שניות). דוגמאות לסוגי תורים: - [Redis](https://redis.io/) is useful as a simple message broker but messages can be lost. - [RabbitMQ](https://www.rabbitmq.com/) is popular but requires you to adapt to the 'AMQP' protocol and manage your own nodes. - [Amazon SQS](https://aws.amazon.com/sqs/) is hosted but can have high latency and has the possibility of messages being delivered twice. ### תורי משימות (Task Queues) תורי משימות מקבלים משימות לצד המידע הרלוונטי שלהן, מריצים אותן, ושולחים את התוצאות. הם יכולים לתמוך ב-scheduling, כלומר להריץ משימה כל זמן מסוים או בשעה קבועה. בנוסף, הם יכולים להריץ משימות כבדות מבחינה חישובית ברקע. - [Celery](https://docs.celeryproject.org/en/stable/) has support for scheduling and primarily has python support. ### Back Pressure אם התור מתחיל לגדול באופן משמעותי מעבר לקצב שבו ה-workers מסוגלים לעבד, גודל התור יכול להיות מעבר למה שפנוי לנו בזיכרון, מה שיגרום ל-cache misses, יותר קריאות מהדיסק, וביצועים נמוכים יותר. [Back pressure](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html) יכול לעזור באמצעות הגדלת גודל התור, מה ששומר על קצב הטיפול בבקשות לכאלו שכבר בתוך התור. אם התור מתמלא, השרת מפסיק לקבל עבודות חדשות ומחזיר ללקוח שגיאת HTTP 503 (עסוק). הלקוח יכול לנסות שוב לאחר זמן המתנה הולך וגדל כמו [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff). ### חסרונות: asynchronism ### מקורות וקריאה נוספת * [It's all a numbers game](https://www.youtube.com/watch?v=1KRYH75wgy4) * [Applying back pressure when overloaded](http://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html) * [Little's law](https://en.wikipedia.org/wiki/Little%27s_law) * [What is the difference between a message queue and a task queue?](https://www.quora.com/What-is-the-difference-between-a-message-queue-and-a-task-queue-Why-would-a-task-queue-require-a-message-broker-like-RabbitMQ-Redis-Celery-or-IronMQ-to-function)
## תקשורת


Source: OSI 7 layer model

### פרוטוקול HTTP פרוטוקול HTTP מאפשר ללקוח ולשרת אינטרנט להחליף מידע בפורמט מוגדר. הוא מבוסס על מבנה של request/response: הלקוח/הדפדפן שולח בקשה לתוכן או פעולה מסוימת, והשרת מחזיר תגובה הכוללת את הנתונים המבוקשים, לצד קוד סטטוס שמצהיר אם הבקשה הצליחה, נכשלה, או הופנתה למקום אחר. פרוטוקול זה הוא self-contained, כלומר כל המידע הנחוץ - הכותרות, סוג הבקשה, הנתונים - עובר כחבילה אחת. לכן החבילות האלה יכולות לעבור דרך router, load balancer בלי שהמתווכים יידרשו להבין את הלוגיקה. לאורך הדרך אותם גורמי ביניים יכולים להוסיף הצפנה, לדחוס נתונים, מבלי שהפרוטוקול עצמו ייפגע. בקשת HTTP טיפוסית מכילה verb (מתודה) ו-resource (נקודת קצה). דוגמאות: | Verb | Description | Idempotent* | Safe | Cacheable | |---|---|---|---|---| | GET | Reads a resource | Yes | Yes | Yes | | POST | Creates a resource or trigger a process that handles data | No | No | Yes if response contains freshness info | | PUT | Creates or replace a resource | Yes | No | No | | PATCH | Partially updates a resource | No | No | Yes if response contains freshness info | | DELETE | Deletes a resource | Yes | No | No | *ניתן לבצע מספר פעמים את אותה הבקשה ולקבל את אותה התוצאה כל פעם. פרוטוקול זה הוא בשכבת האפליקציה, והוא מסתמך על פרוטוקולים בשכבות נמוכות יותר כמו **TCP** ו-**UDP**. #### מקורות וקריאה נוספת * [What is HTTP?](https://www.nginx.com/resources/glossary/http/) * [Difference between HTTP and TCP](https://www.quora.com/What-is-the-difference-between-HTTP-protocol-and-TCP-protocol) * [Difference between PUT and PATCH](https://laracasts.com/discuss/channels/general-discussion/whats-the-differences-between-put-and-patch?page=1) ### פרוטוקול TCP


Source: How to make a multiplayer game

פרוטוקול זה הוא מבוסס מעל [IP network](https://en.wikipedia.org/wiki/Internet_Protocol). החיבור נבנה ונסגר באמצעות [handshake](https://en.wikipedia.org/wiki/Handshaking). כל הפקטות שנשלחות מובטחות להגיע ליעד בדיוק בסדר המקורי שבו הן נשלחו, ובאופן תקין (uncorrupted): - Sequence numbers and [checksum fields](https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Checksum_computation) for each packet - [Acknowledgement](https://en.wikipedia.org/wiki/Acknowledgement_(data_networks)) packets and automatic retransmission אם השולח לא מקבל תשובה תקינה בתוך פרק זמן קצוב, הוא מניח שהמקטע אבד ומשדר אותו שוב. אם יש מספר timeouts כמה פעמים ברצף, אז החיבור נסגר. TCP מממש גם [flow control](https://en.wikipedia.org/wiki/Flow_control_(data)) וגם [congestion control](https://en.wikipedia.org/wiki/Network_congestion#Congestion_control) על מנת לפקח על קצב הנתונים. ההבטחות הללו מוסיפות תזמונים, חישובים, וחבילות בקרה, מה שעלול לגרום לעיכובים וליצור תעבורה פחות מהירה מאשר UDP. כדי לאפשר throughput מהיר, שרתים שומרים הרבה חיבורי TCP פתוחים, מה שמוביל לצריכת זיכרון גבוהה. הבעיה מחריפה כאשר אותו שרת מפעיל חיבורים נפרדים בין התהליכים שלו לבין שירותים פנימיים אחרים, כמו לדוגמה אל שרת [memcached](https://memcached.org/). ביצוע [Connection pooling](https://en.wikipedia.org/wiki/Connection_pool), שמירת אוסף חיבורים פתוחים המשותפים בין כל ה-threads, יכול לסייע ומצמצם את מספר החיבורים האמיתיים וחוסך זיכרון. בנוסף, ניתן לעבור ל-UDP היכן שניתן, שם אין שמירה של חיבור. פרוטוקול TCP שימושי לאפליקציות שדורשות אמינות גבוהה, על פני מהירות וזמן תגובה מיידי. דוגמאות: שרתי HTTP, FTP, SMTP, SSH או MySQL בוחרים ב-TCP. שיקולים לבחירה בפרוטוקול זה על פני UDP: ### פרוטוקול UDP


Source: How to make a multiplayer game

בפרוטוקול זה אין חיבור קבוע בין הלקוח לשרת. כל חבילה (Datagram) נשלחת בנפרד, ללא מעקב אחרי מה שכבר נשלח. החבילות יכולות להגיע ליעד בסדר שונה, או בכלל לא. אין תמיכה ב-congestion control. עם זאת, כיוון שאין את כל ההבטחות שכלולות ב-TCP, ה-overhead קטן מאוד ולכן UDP יעיל ומהיר יותר. האפליקציה צריכה להתמודד בעצמה עם איבוד חבילות וסדר החבילות. ב-UDP מתאפשר שידור (broadcast) - שליחת חבילה אחת לכל המכשירים של אותו ה-subnet. זה שימושי בשילוב עם [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) כיוון שבתחילת התהליך המחשב עדיין לא קיבל כתובת IP, ולכן אינו יודע למי לפנות ישירות. הוא משדר הודעה ברשת וכל שרת DHCP שומע את ההודעה, בוחר להשיב ומציע כתובת IP. ב-TCP זה לא היה עובד, כי שם אנו נדרשים לדעת כתובת יעד ספציפית. פרוטוקול זה הינו פחות אמין אבל עובד בצורה טובה במקרים של real time כמו VoIP, וידאו צ'אט, streaming, ומשחקים מרובי משתתפים. מתי הוא עדיף על TCP? #### מקורות וקריאה נוספת: TCP and UDP - [Networking for game programming](http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/) - [Key differences between TCP and UDP protocols](http://www.cyberciti.biz/faq/key-differences-between-tcp-and-udp-protocols/) - [Difference between TCP and UDP](http://stackoverflow.com/questions/5970383/difference-between-tcp-and-udp) - [Transmission control protocol](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) - [User datagram protocol](https://en.wikipedia.org/wiki/User_Datagram_Protocol) - [Scaling memcache at Facebook](http://www.cs.bu.edu/~jappavoo/jappavoo.github.com/451/papers/memcache-fb.pdf)
### פרוטוקול RPC


Source: Crack the system design interview

ב-RPC, לקוח גורם לריצה של פונקציה במרחב כתובות שונה, לרוב על שרת מרוחק, כאילו הייתה פונקציה מקומית בקוד שלו. הלקוח פשוט קורא לפונקציה, ומאחורי הקלעים ישנה ספריה אשר מטפלת באריזה (serialization) של הפרמטרים, שליחת הבקשה ב-TCP, קבלת התשובה ותרגומה לאובייקט. RPC הינו לרוב איטי יותר ופחות אמין מאשר קריאה מקומית, לכן חשוב לסמן קריאות כאלו כ-RPC כדי שמפתחים יבינו שהן עלולות להיכשל או להתעכב. תשתיות נפוצות כוללות את [Protobuf](https://developers.google.com/protocol-buffers/), [Thrift](https://thrift.apache.org/), [Avro](https://avro.apache.org/docs/current/). פרוטוקול זה מבוסס על בקשה-תגובה: קריאות RPC לדוגמה: ``` GET /someoperation?data=anId POST /anotheroperation { "data":"anId"; "anotherdata": "another value" } ``` פרוטוקול מתמקד בהגדרת התנהגות של פונקציות כאילו הן חלק מהממשק המקומי של השפה. הקריאה עובדת מאחורי הקלעים לשרת אחר, אבל למפתח זה נראה כמו פונקציה רגילה. RPC מאפשר גם שליטה מוחלטת על הפונקציונליות והתקשורת, ומתאים לפיתוח מערכת פנימית. נרצה לבחור בספריה משלנו (SDK) כאשר: ממשקים שעוקבים אחרי פרוטוקול **REST** נוטים להיות יותר בשימוש עבור APIים פומביים. #### חסרונות: RPC ### ממשק REST בממשק REST הלקוח מבקש סט מסוים של משאבים המנוהלים על ידי השרת. השרת מספק ייצוג של המשאבים ופעולות שניתן לעשות עליהם. כל התקשורת היא stateless ו-cacheable. יש 4 תכונות של ממשק RESTful: קריאות REST לדוגמה: ``` GET /someresources/anId PUT /someresources/anId {"anotherdata": "another value"} ``` הפרוטוקול מתמקד בחשיפת הנתונים בתור משאבים (בשונה מהפעלת פונקציות ב-RPC) באמצעות כתובת URL קבועה. הלקוח שולח בקשות HTTP סטנדרטיות והשרת מחזיר את התשובה המתאימה. זה מאפשר coupling נמוך בין הלקוח לשרת: הלקוח רק צריך לדעת אילו URI-ים קיימים ואילו פעלים מותר להפעיל (GET, POST), אין תלות בשפת התכנות של השרת או בספריות מיוחדות. REST מספק ממשק אחיד לייצוג הפעולות - [representation through headers](https://github.com/for-GET/know-your-http-well/blob/master/headers.md). כיוון שהוא stateless, קל לפרוס עותקים רבים שלו מאחורי load balancer ולבזר את העומסים. #### Disadvantage(s): REST ### השוואה בין קריאות RPC ובין REST | Operation | RPC | REST | |---|---|---| | Signup | **POST** /signup | **POST** /persons | | Resign | **POST** /resign
{
"personid": "1234"
} | **DELETE** /persons/1234 | | Read a person | **GET** /readPerson?personid=1234 | **GET** /persons/1234 | | Read a person’s items list | **GET** /readUsersItemsList?personid=1234 | **GET** /persons/1234/items | | Add an item to a person’s items | **POST** /addItemToUsersItemsList
{
"personid": "1234";
"itemid": "456"
} | **POST** /persons/1234/items
{
"itemid": "456"
} | | Update an item | **POST** /modifyItem
{
"itemid": "456";
"key": "value"
} | **PUT** /items/456
{
"key": "value"
} | | Delete an item | **POST** /removeItem
{
"itemid": "456"
} | **DELETE** /items/456 |

Source: Do you really know why you prefer REST over RPC

#### מקורות וקריאה נוספת: REST and RPC - [Do you really know why you prefer REST over RPC](https://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/) - [When are RPC-ish approaches more appropriate than REST?](http://programmers.stackexchange.com/a/181186) - [REST vs JSON-RPC](http://stackoverflow.com/questions/15056878/rest-vs-json-rpc) - [Debunking the myths of RPC and REST](https://web.archive.org/web/20170608193645/http://etherealbits.com/2012/12/debunking-the-myths-of-rpc-rest/) - [What are the drawbacks of using REST](https://www.quora.com/What-are-the-drawbacks-of-using-RESTful-APIs) - [Crack the system design interview](http://www.puncsky.com/blog/2016-02-13-crack-the-system-design-interview) - [Thrift](https://code.facebook.com/posts/1468950976659943/) - [Why REST for internal use and not RPC](http://arstechnica.com/civis/viewtopic.php?t=1190508)