דלג לתוכן הראשי
Tech Degree IL

איך להתכונן לראיון System Design

עידן חן2026-03-2511 דקות
System DesignInterviewsCareer

איך להתכונן לראיון System Design

ב-2019, Slack עבר 100 מיליון הודעות ביום. ב-2020 — עם COVID — הם עלו ל-1.5 מיליארד הודעות ביום בשיא. מי שתכנן את הארכיטקטורה ב-2019 צריך היה לחשוב: "מה קורה אם התנועה מכפילה את עצמה פי 15 בחודש?" מי שלא חשב — היה נלחץ ב-March 2020.

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

מה בודקים — ולמה אין תשובה "נכונה"

בניגוד לראיון Algorithms שיש בו תשובה מיטבית, ב-System Design אין תשובה אחת נכונה. מראיין טוב לא מחפש שתגידו "Kafka". הוא מחפש:

יכולת לפרק בעיה מורכבת — לקחת "תכנן Twitter" ולשבור אותה לcomponents ניתנים לניהול.

מודעות ל-tradeoffs — "אם נשתמש ב-NoSQL, מרוויחים X אבל מפסידים Y". לא רק לדעת מה לבחור — לדעת מה המחיר.

thinking at scale — "מה קורה כש-1 מיליון users מתחברים בו-זמנית?" לא לתכנן לכמות users הנוכחית — לתכנן לעשר פעמים ממנה.

communication — לחשוב בקול. המראיין לא יכול לקרוא מחשבות. אם לא מסבירים למה בוחרים מה שבוחרים — הוא לא יכול לתת לכם credit.

ה-Framework: 4 שלבים לכל שאלה

שלב 1: Requirements (5-10 דקות)

לפני שציירים כלום — שואלים. זה לא אות חולשה, זה אות בשלות.

text
שאלות חובה:
├── Scale: "כמה users? כמה requests/שנייה? כמה data?"
├── Availability: "מה ה-SLA? 99.9% = 9 שעות downtime/שנה. 99.99% = 1 שעה"
├── Consistency: "האם read-after-write חשוב? האם eventual consistency OK?"
├── Latency: "מה זמן תגובה מקסימלי נסבל?"
└── Scope: "מה ה-features הקריטיים לתכנן עכשיו?"

דוגמה: "תכנן URL Shortener."

שאלות חיוניות: כמה URLs מקצרים ביום? כמה redirects? האם URL ניתן לשינוי אחרי יצירה? האם צריך analytics? כמה זמן שומרים URL? האם צריך vanity URLs (custom slugs)?

שלב 2: High-Level Design (10-15 דקות)

ציירו את הblocks הגדולים. לא לרדת לפרטים עדיין.

שלב 3: Deep Dive (15-20 דקות)

בחרו 1-2 components ותצללו לעומק. מה schema הDB? מה אסטרטגיית הcaching? איך מייצרים short URLs?

שלב 4: Bottlenecks ו-Failure Modes (5 דקות)

"איפה המערכת הזו תיפול?" DB write bottleneck? Cache invalidation? Single point of failure?

נושאי ליבה שחוזרים בכל ראיון

Scaling

Vertical Scaling — שרת חזק יותר. פשוט, אבל יש ceiling. השרת הכי חזק בעולם עדיין מוגבל.

Horizontal Scaling — יותר servers מאחורי Load Balancer. דורש שה-app יהיה stateless — כל request יכול להגיע לכל server.

Database Sharding — פיצול ה-DB לכמה מכונות לפי key. ה-challenge: איך מחלקים? לפי user_id? לפי geography? כל גישה עם tradeoffs שונים.

שיטת Shardingיתרוןחיסרון
Range-based (user 1-1M → shard 1)פשוט לממשhot spots: user IDs חדשים כולם ב-shard אחד
Hash-based (hash(user_id) % N)פיזור אחידקשה להוסיף shards — rehashing
Directory-based (lookup table)גמישה-directory עצמו bottleneck
Geographic (EU → shard EU)data localityלא אחיד אם יש market גדול

Caching

Caching הוא הכלי הראשון שמשתמשים בו לבעיות read performance. הרעיון: תוצאות יקרות (DB queries, API calls) נשמרות בmemory מהיר (Redis, Memcached) לזמן מוגבל.

אסטרטגיות invalidation — הבעיה הקשה:

  • TTL (Time To Live) — data פג תוקף אחרי X זמן. פשוט, אבל data יכול להיות stale עד X.
  • Cache-aside — app מנהל cache ידנית: בדוק cache → miss → קרא DB → כתוב לcache.
  • Write-through — כל write לDB → write לcache במקביל. תמיד fresh, אבל write overhead.
  • Cache invalidation on update — כשDB מתעדכן, מחקו את ה-cache key. פשוט בעיקרון, מורכב כשיש כמה servers.

Phil Karlton אמר: "There are only two hard things in Computer Science: cache invalidation and naming things." זה לא בדיחה — cache invalidation bugs גרמו ל-incidents בכל חברה גדולה.

Database Design — SQL vs NoSQL

השאלה לא "SQL טוב יותר מNoSQL". השאלה היא: "מה ה-access patterns שלי?" SQL מצוין עם joins מורכבים, ACID transactions, ושאילתות שלא ידועות מראש. NoSQL מצוין עם scale-out אופקי, schemaless data, ו-access patterns פשוטים ויציבים.

קריטריוןSQL (PostgreSQL, MySQL)NoSQL (MongoDB, DynamoDB, Cassandra)
Schemaקפיד, migration מוגדרגמיש, schemaless
TransactionsACID מלאמוגבל, בד"כ per-document
Scalevertical (בעיקר), read replicashorizontal, sharding built-in
Joinsnative, efficientלא נתמך או יקר
Query flexibilityגבוהה — SQL שרירותינמוכה — צריך לדעת queries מראש
Consistencystrong consistencyconfigurable (eventual↔strong)

הכלל הפשוט: אם אתם יודעים את access patterns מראש ולא צריכים joins — NoSQL. אם אתם צריכים flexibility בquerying — SQL.

Message Queues

Kafka, RabbitMQ, AWS SQS — מה הם ולמה חשובים?

כשservice A צריך לקרוא לservice B, ויש שתי אפשרויות:

Synchronous (HTTP call): A מחכה לתשובה מB. אם B איטי — A איטי. אם B נפל — A נכשל.

Asynchronous via Queue: A שולח message לqueue וממשיך. B קורא מה-queue כשהוא מוכן. אם B נפל — message נשאר ב-queue עד שB חוזר.

text
שימושים קלאסיים ל-Message Queue:

Order completed → [Queue] → Email Service
                          → Inventory Service
                          → Analytics Service
                          → Fulfillment Service

כל אחד קורא בקצב שלו, נכשל בלי להוריד אחרים.

Kafka מצוין לevent streaming בvolume גבוה (millions/sec). RabbitMQ מצוין לtask queues עם routing מורכב. SQS — fully managed, פחות features, אבל אפסי תחזוקה.

CAP Theorem

בsystem distributed בלתי אפשרי לקבל את שלושתם בו-זמנית:

C — Consistency: כל read מחזיר את הwrite האחרון (או error). A — Availability: כל request מקבל תשובה (לא error). P — Partition Tolerance: המערכת ממשיכה לעבוד גם כש-nodes מנותקים.

בpractice, Partition Tolerance הוא הכרחי בכל distributed system (רשת תמיד יכולה להיכשל). אז הבחירה האמיתית היא CP vs AP:

  • CP: כשיש partition — מחזיר error (לא ריספונסיבי) במקום תשובה שאולי stale. בנקאות, transactions.
  • AP: כשיש partition — מחזיר תשובה שאולי לא עדכנית. Social feeds, shopping cart.

URL Shortener — walkthrough מלא

"תכנן URL Shortener כמו bit.ly"

Requirements שנקבל:

  • 100M URLs חדשים ביום (1200 writes/sec)
  • 10B redirects ביום (115K reads/sec — read-heavy)
  • URLs נשמרים 5 שנים
  • זמן redirect < 50ms ב-p99
  • 99.99% availability

Estimation: 100M URLs/day × 365 × 5 = 182.5B URLs. ממוצע URL: ~500 bytes → כ-91TB storage.

Short Code Generation — אחת הבעיות הנפוצות:

python
import hashlib
import base62

def generate_short_code(long_url: str, user_id: str) -> str:
    # הוסיפו timestamp למניעת collisions
    input_str = f"{long_url}:{user_id}:{time.time()}"
    
    # MD5 hash של ה-input
    hash_bytes = hashlib.md5(input_str.encode()).digest()
    
    # המרה ל-base62 (a-z, A-Z, 0-9) — 8 תווים = 62^8 = 218 טריליון אפשרויות
    short_code = base62.encodebytes(hash_bytes)[:8]
    
    return short_code

Caching Strategy — read-heavy בvery much:

80/20 rule: 20% מה-URLs מייצרים 80% מה-traffic. Cache את ה-20% החם ב-Redis. 115K reads/sec — רוב מהcache.

python
async def redirect(short_code: str) -> str:
    # Cache-aside pattern
    cached = await redis.get(f"url:{short_code}")
    if cached:
        return cached

    # Cache miss — לDB
    url = await db.get_url(short_code)
    if not url:
        raise NotFoundException()

    # Cache for 24h (hot URLs stay hot)
    await redis.setex(f"url:{short_code}", 86400, url.original_url)
    return url.original_url

הטעויות הנפוצות בראיון

לא לשאול שאלות: "תכנן Twitter" יכול להיות 50M users או 500M users. עם consistency מחמיר או eventual. עם Reels/Stories או בלי. בלי לשאול — אתם מתכננים מערכת שאולי לא מתאימה לרצון המראיין.

לקפוץ לפתרון לפני שהבנתם: "נשתמש ב-Kafka" — למה? Kafka מה-place הנכון כאן? מה הוא פותר? מי שפותח עם answers לפני שמבין את הbusiness constraints — מראה pattern חשיבה שגוי.

לדבר רק על happy path: המראיין רוצה לראות שאתם חושבים על failures. מה קורה כש-DB ראשי נפל? כשCache flush? כשthird-party API לא עונה? כשרשת מפוצלת?

לא לדבר בקול: המראיין לא יכול לתת לכם credit על מחשבות שלא אמרתם. גם אם ה-intuition שלכם נכון — אם לא אמרתם אותו, הוא לא נמדד.

תרגול אפקטיבי: קחו שאלה (Design WhatsApp, Design YouTube, Design Rate Limiter), שבו 45 דקות, ותעברו על כל 4 שלבים בקול. לא בראש — בקול. הבדל עצום בין "אני יודע לתכנן את זה" לבין "אני יודע להסביר לאחרים איך לתכנן את זה."

חידון

מה זה 'Thundering Herd' ואיך מונעים אותו?