לדלג לתוכן

4.1 מדרגיות וזמינות הרצאה

מדרגיות וזמינות

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


מדרגיות - Scalability

מדרגיות היא היכולת של מערכת להתמודד עם עומס גדל יותר.

הרחבה אנכית - Vertical Scaling

הוספת משאבים לשרת הקיים: יותר CPU, יותר RAM, דיסק מהיר יותר.

שרת קטן: 2 CPU, 4GB RAM  →  שרת גדול: 32 CPU, 128GB RAM

יתרונות: פשוט לביצוע, לא דורש שינוי בקוד.

חסרונות:
- יש גבול - לא ניתן להוסיף ללא סוף
- downtime בעת שדרוג
- יקר מאוד בגדלים גדולים
- נקודת כשל יחידה - שרת אחד שנופל = מערכת מתה

הרחבה אופקית - Horizontal Scaling

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

שרת אחד גדול  →  10 שרתים קטנים + Load Balancer

יתרונות:
- ניתן להוסיף ללא סוף (תיאורטית)
- fault tolerance - שרת אחד נופל, תשעה ממשיכים
- עלות נמוכה יותר בסולם

חסרונות:
- מורכבות - צריך load balancer, session management, data consistency

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


זמינות - Availability

זמינות מודדת כמה זמן המערכת עובדת מתוך הזמן הכולל.

זמינות = זמן פעיל / זמן כולל × 100%

"Five Nines" ומשמעותם

זמינות downtime בשנה
99% 3.65 ימים
99.9% 8.7 שעות
99.99% 52 דקות
99.999% 5.25 דקות

שירותים קריטיים (בנקים, בתי חולים) דורשים 99.999% (Five Nines).

איך משיגים זמינות גבוהה?

Redundancy: אין נקודת כשל יחידה. כל רכיב קריטי כפול.

[Load Balancer] → [App Server 1]
                → [App Server 2]
                → [App Server 3]

[Primary DB] ↔ [Replica DB 1]
             ↔ [Replica DB 2]

Health Checks: בדיקה קבועה שכל שרת פעיל. שרת שנכשל - מסירים אותו אוטומטית.

Graceful Degradation: כשחלק נכשל, המערכת ממשיכה לעבוד בצורה מוגבלת - לא קורסת לגמרי.


CAP Theorem - משפט CAP

משפט CAP קובע שמסד נתונים מבוזר יכול להבטיח לכל היותר שניים מתוך שלושה:

C - Consistency - עקביות: כל קריאה מחזירה את הכתיבה האחרונה או שגיאה.

A - Availability - זמינות: כל בקשה מקבלת תשובה (לא בהכרח עדכנית).

P - Partition Tolerance - סבילות לחלוקה: המערכת ממשיכה לעבוד גם כשיש תקלת רשת בין nodes.

החלוקה (P) היא בלתי נמנעת ברשתות אמיתיות. לכן בפועל בוחרים בין CP ל-AP:

CP (Consistency + Partition Tolerance):
עדיפות לדיוק על פני זמינות. אם לא ניתן להחזיר נתון עדכני - מחזירים שגיאה.
דוגמה: MongoDB בהגדרת קריאה מהprimary, HBase.

AP (Availability + Partition Tolerance):
עדיפות לזמינות על פני דיוק. עשוי להחזיר נתון לא עדכני.
דוגמה: DynamoDB, CouchDB, Cassandra.

Eventual Consistency - עקביות סופית

מערכות AP בדרך כלל מציעות "eventual consistency": לאחר תקופה (בדרך כלל מילישניות עד שניות), כל הnodes יסכימו על אותם הנתונים.

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


Circuit Breaker - מפסק עגול

הבעיה: שירות A קורא לשירות B. B נופל ומגיב לאט. A ממתין. יש לA 100 threads. כולם ממתינים. A קורס.

הפתרון: Circuit Breaker - מעקב אחר שגיאות, ואם עוברים סף - "מפסקים" קריאות ל-B ומחזירים שגיאה מיידית.

class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.failure_count = 0
        self.last_failure_time = None
        self.state = "closed"  # closed = עובד, open = מפסיק

    def call(self, func, *args, **kwargs):
        if self.state == "open":
            import time
            if time.time() - self.last_failure_time > self.timeout:
                self.state = "half-open"
            else:
                raise Exception("Circuit Breaker פתוח - שירות לא זמין")
        try:
            result = func(*args, **kwargs)
            if self.state == "half-open":
                self.state = "closed"
                self.failure_count = 0
            return result
        except Exception as e:
            self.failure_count += 1
            import time
            self.last_failure_time = time.time()
            if self.failure_count >= self.failure_threshold:
                self.state = "open"
            raise


# שימוש
breaker = CircuitBreaker()

def call_notification_service(user_id: int):
    return breaker.call(
        notification_service.send,
        user_id,
        "משימה עודכנה"
    )

סיכום

עיקרון מטרה
Vertical Scaling פשוט אבל מוגבל
Horizontal Scaling גמיש ואמין יותר
Availability כמה זמן המערכת עובדת
CAP Theorem עקביות vs זמינות
Circuit Breaker מניעת כשל מדורתי