Dev Logs
/System Design/ Chapter 20: Real-World System Design
Chapters
  • 01Chapter 1: Introduction to System Design
  • 02Chapter 2: Load Balancing and Traffic Distribution
  • 03Chapter 3: Caching Strategies and Implementation
  • 04Chapter 4: Database Design and Scaling
  • 05Chapter 5: API Design and Gateway Patterns
  • 06Chapter 6: Message Queues and Event Processing
  • 07Chapter 7: Microservices Architecture
  • 08Chapter 8: Distributed Systems Fundamentals
  • 09Chapter 9: Observability & Monitoring
  • 10Chapter 10: Security & Authentication
  • 11Chapter 11: Horizontal vs Vertical Scaling
  • 12Chapter 12: Content Delivery & Edge Computing
  • 13Chapter 13: Reliability Patterns
  • 14Chapter 14: Data Modeling & Storage
  • 15Chapter 15: Consistency and Consensus
  • 16Chapter 16: Deployment Strategies
  • 17Chapter 17: Disaster Recovery and Business Continuity
  • 18Chapter 18: Performance Optimization
  • 19Chapter 19: Testing Strategies
  • 20Chapter 20: Real-World System Design
    • Overview
    • WhatsApp Architecture
    • System Overview
    • Architecture Design
    • Key Design Decisions
    • YouTube Architecture
    • System Overview
    • Architecture Design
    • Key Design Decisions
    • Uber Architecture
    • System Overview
    • Architecture Design
    • Key Design Decisions
    • Netflix Architecture
    • System Overview
    • Architecture Design
    • Key Design Decisions
    • Best Practices from Real-World Systems
    • Architecture Principles
    • Technology Choices
    • Common Pitfalls and Solutions
    • Scalability Pitfalls
    • Reliability Pitfalls
    • Performance Pitfalls
    • Security Pitfalls
    • Key Takeaways
    • Design Philosophy
    • Evolution Patterns
    • Success Metrics
  • 21Chapter 21: System Design Interview Preparation
All chapters

Chapter 20: Real-World System Design

Overview

This chapter examines real-world system architectures of major tech companies, analyzing their design decisions, trade-offs, and evolution over time. We'll explore how theoretical concepts are applied in practice to solve massive scale challenges.

WhatsApp Architecture

System Overview

WhatsApp Scale (2014 Acquisition):

  • 450 million users
  • 50 billion messages per day
  • 32 engineers
  • $19 billion acquisition

Architecture Design

High-Level Architecture:

[Mobile Apps] → [Load Balancer] → [Chat Servers] → [Message Queue]
                                        ↓              ↓
[Push Notifications] ← [Presence Service] ← [Database Cluster]

Core Components Implementation (Python)

python
import asyncio
import time
import json
import hashlib
from typing import Dict, List, Optional, Set
from dataclasses import dataclass, asdict
from enum import Enum
import redis
from collections import defaultdict

class MessageStatus(Enum):
    SENT = "sent"
    DELIVERED = "delivered"
    READ = "read"

class UserStatus(Enum):
    ONLINE = "online"
    OFFLINE = "offline"
    AWAY = "away"

@dataclass
class Message:
    id: str
    from_user: str
    to_user: str
    content: str
    timestamp: float
    message_type: str = "text"
    status: MessageStatus = MessageStatus.SENT
    encrypted: bool = True

@dataclass
class User:
    user_id: str
    phone_number: str
    status: UserStatus
    last_seen: float
    device_tokens: List[str]
    public_key: str

class MessageRouter:
    """Routes messages to appropriate chat servers based on user hash"""
    
    def __init__(self, num_servers: int = 100):
        self.num_servers = num_servers
        self.server_connections: Dict[int, str] = {}  # server_id -> connection_string
    
    def get_server_for_user(self, user_id: str) -> int:
        """Consistent hashing to determine which server handles a user"""
        hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
        return hash_value % self.num_servers
    
    def route_message(self, message: Message) -> tuple[int, int]:
        """Route message to appropriate servers for sender and receiver"""
        sender_server = self.get_server_for_user(message.from_user)
        receiver_server = self.get_server_for_user(message.to_user)
        return sender_server, receiver_server

class ChatServer:
    """Individual chat server handling a subset of users"""
    
    def __init__(self, server_id: int, redis_client):
        self.server_id = server_id
        self.redis = redis_client
        self.active_connections: Dict[str, asyncio.WebSocketServerProtocol] = {}
        self.user_sessions: Dict[str, Dict] = {}
        self.message_queue = asyncio.Queue()
        
        # Start background tasks
        asyncio.create_task(self._process_message_queue())
        asyncio.create_task(self._heartbeat_checker())
    
    async def handle_user_connection(self, websocket, user_id: str):
        """Handle new user connection"""
        try:
            # Register connection
            self.active_connections[user_id] = websocket
            self.user_sessions[user_id] = {
                'connected_at': time.time(),
                'last_heartbeat': time.time()
            }
            
            # Update user status to online
            await self._update_user_status(user_id, UserStatus.ONLINE)
            
            # Send pending messages
            await self._send_pending_messages(user_id)
            
            # Listen for messages
            async for message in websocket:
                await self._handle_incoming_message(user_id, message)
        
        except Exception as e:
            print(f"Connection error for user {user_id}: {e}")
        
        finally:
            # Clean up connection
            if user_id in self.active_connections:
                del self.active_connections[user_id]
            if user_id in self.user_sessions:
                del self.user_sessions[user_id]
            
            # Update user status to offline
            await self._update_user_status(user_id, UserStatus.OFFLINE)
    
    async def _handle_incoming_message(self, from_user: str, raw_message: str):
        """Process incoming message from user"""
        try:
            data = json.loads(raw_message)
            
            if data['type'] == 'message':
                message = Message(
                    id=data['id'],
                    from_user=from_user,
                    to_user=data['to_user'],
                    content=data['content'],
                    timestamp=time.time(),
                    message_type=data.get('message_type', 'text')
                )
                
                await self.message_queue.put(message)
            
            elif data['type'] == 'heartbeat':
                self.user_sessions[from_user]['last_heartbeat'] = time.time()
            
            elif data['type'] == 'message_ack':
                await self._handle_message_acknowledgment(data['message_id'], data['status'])
        
        except Exception as e:
            print(f"Error handling message from {from_user}: {e}")
    
    async def _process_message_queue(self):
        """Background task to process outgoing messages"""
        while True:
            try:
                message = await self.message_queue.get()
                await self._deliver_message(message)
            except Exception as e:
                print(f"Error processing message queue: {e}")
    
    async def _deliver_message(self, message: Message):
        """Deliver message to recipient"""
        # Store message in database
        await self._store_message(message)
        
        # Try to deliver to online user
        if message.to_user in self.active_connections:
            try:
                websocket = self.active_connections[message.to_user]
                await websocket.send(json.dumps({
                    'type': 'message',
                    'message': asdict(message)
                }))
                
                # Update message status to delivered
                message.status = MessageStatus.DELIVERED
                await self._update_message_status(message.id, MessageStatus.DELIVERED)
            
            except Exception as e:
                print(f"Failed to deliver message to {message.to_user}: {e}")
                # Store for later delivery
                await self._store_pending_message(message)
        else:
            # User offline, store for later delivery
            await self._store_pending_message(message)
            
            # Send push notification
            await self._send_push_notification(message)
    
    async def _store_message(self, message: Message):
        """Store message in Redis"""
        message_key = f"message:{message.id}"
        await self.redis.hset(message_key, mapping=asdict(message))
        await self.redis.expire(message_key, 86400 * 30)  # 30 days retention
        
        # Add to user's message list
        user_messages_key = f"user_messages:{message.to_user}"
        await self.redis.lpush(user_messages_key, message.id)
        await self.redis.ltrim(user_messages_key, 0, 1000)  # Keep last 1000 messages
    
    async def _store_pending_message(self, message: Message):
        """Store message for offline user"""
        pending_key = f"pending:{message.to_user}"
        await self.redis.lpush(pending_key, message.id)
    
    async def _send_pending_messages(self, user_id: str):
        """Send all pending messages to newly connected user"""
        pending_key = f"pending:{user_id}"
        
        while True:
            message_id = await self.redis.rpop(pending_key)
            if not message_id:
                break
            
            # Get message details
            message_key = f"message:{message_id}"
            message_data = await self.redis.hgetall(message_key)
            
            if message_data and user_id in self.active_connections:
                try:
                    websocket = self.active_connections[user_id]
                    await websocket.send(json.dumps({
                        'type': 'message',
                        'message': message_data
                    }))
                    
                    # Update message status
                    await self._update_message_status(message_id, MessageStatus.DELIVERED)
                
                except Exception as e:
                    # Put message back if delivery failed
                    await self.redis.rpush(pending_key, message_id)
                    break
    
    async def _send_push_notification(self, message: Message):
        """Send push notification for offline user"""
        # Get user's device tokens
        user_key = f"user:{message.to_user}"
        device_tokens = await self.redis.lrange(f"{user_key}:devices", 0, -1)
        
        for token in device_tokens:
            # Send push notification (simplified)
            notification_payload = {
                'token': token,
                'title': f"Message from {message.from_user}",
                'body': message.content[:50] + "..." if len(message.content) > 50 else message.content,
                'data': {
                    'message_id': message.id,
                    'from_user': message.from_user
                }
            }
            
            # In real implementation, this would use FCM/APNS
            print(f"Sending push notification: {notification_payload}")
    
    async def _update_user_status(self, user_id: str, status: UserStatus):
        """Update user's online status"""
        user_key = f"user:{user_id}"
        await self.redis.hset(user_key, mapping={
            'status': status.value,
            'last_seen': time.time()
        })
        
        # Notify contacts about status change
        await self._broadcast_status_update(user_id, status)
    
    async def _broadcast_status_update(self, user_id: str, status: UserStatus):
        """Broadcast user status to their contacts"""
        # Get user's contacts
        contacts_key = f"contacts:{user_id}"
        contacts = await self.redis.smembers(contacts_key)
        
        status_update = {
            'type': 'status_update',
            'user_id': user_id,
            'status': status.value,
            'timestamp': time.time()
        }
        
        for contact_id in contacts:
            if contact_id in self.active_connections:
                try:
                    websocket = self.active_connections[contact_id]
                    await websocket.send(json.dumps(status_update))
                except Exception as e:
                    print(f"Failed to send status update to {contact_id}: {e}")
    
    async def _heartbeat_checker(self):
        """Check for inactive connections"""
        while True:
            try:
                current_time = time.time()
                inactive_users = []
                
                for user_id, session in self.user_sessions.items():
                    if current_time - session['last_heartbeat'] > 30:  # 30 seconds timeout
                        inactive_users.append(user_id)
                
                # Disconnect inactive users
                for user_id in inactive_users:
                    if user_id in self.active_connections:
                        await self.active_connections[user_id].close()
                
                await asyncio.sleep(10)  # Check every 10 seconds
            
            except Exception as e:
                print(f"Error in heartbeat checker: {e}")
    
    async def _handle_message_acknowledgment(self, message_id: str, status: str):
        """Handle message read/delivery acknowledgment"""
        await self._update_message_status(message_id, MessageStatus(status))
    
    async def _update_message_status(self, message_id: str, status: MessageStatus):
        """Update message delivery status"""
        message_key = f"message:{message_id}"
        await self.redis.hset(message_key, 'status', status.value)
    
    def get_stats(self) -> Dict:
        """Get server statistics"""
        return {
            'server_id': self.server_id,
            'active_connections': len(self.active_connections),
            'queue_size': self.message_queue.qsize(),
            'active_users': list(self.active_connections.keys())
        }

class WhatsAppCluster:
    """Main WhatsApp cluster coordinator"""
    
    def __init__(self, num_servers: int = 100):
        self.router = MessageRouter(num_servers)
        self.chat_servers: Dict[int, ChatServer] = {}
        self.redis_cluster = {}  # Redis cluster connections
        
        # Initialize chat servers
        for i in range(num_servers):
            redis_client = redis.Redis(host='localhost', port=6379, db=i % 16)
            self.chat_servers[i] = ChatServer(i, redis_client)
    
    async def route_user_connection(self, user_id: str, websocket):
        """Route user connection to appropriate server"""
        server_id = self.router.get_server_for_user(user_id)
        chat_server = self.chat_servers[server_id]
        await chat_server.handle_user_connection(websocket, user_id)
    
    async def send_message(self, message: Message):
        """Send message through the cluster"""
        sender_server, receiver_server = self.router.route_message(message)
        
        # Add message to receiver's server queue
        receiver_chat_server = self.chat_servers[receiver_server]
        await receiver_chat_server.message_queue.put(message)
    
    def get_cluster_stats(self) -> Dict:
        """Get cluster-wide statistics"""
        total_connections = 0
        total_queue_size = 0
        server_stats = []
        
        for server in self.chat_servers.values():
            stats = server.get_stats()
            server_stats.append(stats)
            total_connections += stats['active_connections']
            total_queue_size += stats['queue_size']
        
        return {
            'total_servers': len(self.chat_servers),
            'total_active_connections': total_connections,
            'total_queue_size': total_queue_size,
            'server_stats': server_stats
        }

Key Design Decisions

1. Erlang/OTP Choice:

  • Actor Model: Each user connection as lightweight process
  • Fault Tolerance: "Let it crash" philosophy
  • Hot Code Swapping: Zero-downtime deployments
  • Massive Concurrency: Millions of lightweight processes

2. Minimal Server Infrastructure:

  • FreeBSD: Optimized for network performance
  • Custom Load Balancer: Efficient connection routing
  • Mnesia Database: Distributed Erlang database
  • Horizontal Scaling: Add servers as needed

3. End-to-End Encryption:

  • Signal Protocol: Forward secrecy
  • Key Exchange: Secure key distribution
  • Message Encryption: Client-side encryption
  • Metadata Protection: Minimal server-side data

YouTube Architecture

System Overview

YouTube Scale:

  • 2+ billion logged-in users monthly
  • 1 billion hours watched daily
  • 500 hours uploaded per minute
  • 80+ languages supported

Architecture Design

High-Level Architecture:

[CDN] → [Load Balancer] → [Web Servers] → [Application Servers]
   ↓           ↓              ↓               ↓
[Video Storage] ← [Transcoding] ← [Metadata DB] ← [Analytics]

Video Processing Pipeline (Python)

python
import asyncio
import hashlib
import json
import time
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
import boto3
from concurrent.futures import ThreadPoolExecutor

class VideoStatus(Enum):
    UPLOADING = "uploading"
    PROCESSING = "processing"
    TRANSCODING = "transcoding"
    READY = "ready"
    FAILED = "failed"

class VideoQuality(Enum):
    Q_144P = "144p"
    Q_240P = "240p"
    Q_360P = "360p"
    Q_480P = "480p"
    Q_720P = "720p"
    Q_1080P = "1080p"
    Q_1440P = "1440p"
    Q_2160P = "2160p"

@dataclass
class VideoMetadata:
    video_id: str
    title: str
    description: str
    uploader_id: str
    upload_time: float
    duration: float
    file_size: int
    original_format: str
    status: VideoStatus
    view_count: int = 0
    like_count: int = 0
    dislike_count: int = 0
    tags: List[str] = None

@dataclass
class VideoVariant:
    video_id: str
    quality: VideoQuality
    format: str
    file_path: str
    file_size: int
    bitrate: int
    codec: str
    resolution: Tuple[int, int]

class VideoUploadHandler:
    """Handles video upload and initial processing"""
    
    def __init__(self, storage_client, max_file_size: int = 128 * 1024 * 1024 * 1024):  # 128GB
        self.storage = storage_client
        self.max_file_size = max_file_size
        self.upload_sessions: Dict[str, Dict] = {}
    
    async def initiate_upload(self, metadata: VideoMetadata) -> str:
        """Initiate chunked video upload"""
        upload_id = hashlib.sha256(f"{metadata.video_id}{time.time()}".encode()).hexdigest()
        
        self.upload_sessions[upload_id] = {
            'video_id': metadata.video_id,
            'metadata': metadata,
            'chunks': {},
            'total_chunks': 0,
            'uploaded_chunks': 0,
            'created_at': time.time()
        }
        
        return upload_id
    
    async def upload_chunk(self, upload_id: str, chunk_number: int, 
                          chunk_data: bytes, is_last_chunk: bool = False) -> bool:
        """Upload video chunk"""
        if upload_id not in self.upload_sessions:
            raise ValueError("Invalid upload session")
        
        session = self.upload_sessions[upload_id]
        
        # Store chunk
        chunk_key = f"uploads/{session['video_id']}/chunk_{chunk_number}"
        await self._store_chunk(chunk_key, chunk_data)
        
        session['chunks'][chunk_number] = {
            'size': len(chunk_data),
            'key': chunk_key,
            'uploaded_at': time.time()
        }
        session['uploaded_chunks'] += 1
        
        if is_last_chunk:
            session['total_chunks'] = chunk_number + 1
        
        # Check if upload is complete
        if (session['total_chunks'] > 0 and 
            session['uploaded_chunks'] == session['total_chunks']):
            await self._finalize_upload(upload_id)
        
        return True
    
    async def _store_chunk(self, key: str, data: bytes):
        """Store chunk in object storage"""
        # In real implementation, this would use S3 or similar
        # For demo, we'll simulate storage
        print(f"Storing chunk {key} ({len(data)} bytes)")
    
    async def _finalize_upload(self, upload_id: str):
        """Combine chunks and start processing"""
        session = self.upload_sessions[upload_id]
        video_id = session['video_id']
        
        # Combine chunks into final video file
        final_key = f"raw_videos/{video_id}.original"
        await self._combine_chunks(session['chunks'], final_key)
        
        # Update video status
        metadata = session['metadata']
        metadata.status = VideoStatus.PROCESSING
        
        # Trigger video processing pipeline
        await self._trigger_processing(metadata)
        
        # Clean up upload session
        del self.upload_sessions[upload_id]
    
    async def _combine_chunks(self, chunks: Dict, final_key: str):
        """Combine uploaded chunks into final file"""
        print(f"Combining {len(chunks)} chunks into {final_key}")
        # Implementation would combine chunks in order
    
    async def _trigger_processing(self, metadata: VideoMetadata):
        """Trigger video processing pipeline"""
        # Send to processing queue
        processing_message = {
            'video_id': metadata.video_id,
            'action': 'process',
            'metadata': metadata.__dict__
        }
        
        # In real implementation, this would use SQS/Kafka
        print(f"Triggering processing for video {metadata.video_id}")

class VideoTranscoder:
    """Handles video transcoding to multiple formats and qualities"""
    
    def __init__(self, num_workers: int = 10):
        self.executor = ThreadPoolExecutor(max_workers=num_workers)
        self.transcoding_queue = asyncio.Queue()
        self.quality_profiles = {
            VideoQuality.Q_144P: {'width': 256, 'height': 144, 'bitrate': 100},
            VideoQuality.Q_240P: {'width': 426, 'height': 240, 'bitrate': 300},
            VideoQuality.Q_360P: {'width': 640, 'height': 360, 'bitrate': 700},
            VideoQuality.Q_480P: {'width': 854, 'height': 480, 'bitrate': 1500},
            VideoQuality.Q_720P: {'width': 1280, 'height': 720, 'bitrate': 3000},
            VideoQuality.Q_1080P: {'width': 1920, 'height': 1080, 'bitrate': 6000},
            VideoQuality.Q_1440P: {'width': 2560, 'height': 1440, 'bitrate': 12000},
            VideoQuality.Q_2160P: {'width': 3840, 'height': 2160, 'bitrate': 24000}
        }
        
        # Start worker tasks
        for _ in range(num_workers):
            asyncio.create_task(self._transcoding_worker())
    
    async def transcode_video(self, metadata: VideoMetadata) -> List[VideoVariant]:
        """Transcode video to multiple qualities"""
        # Determine which qualities to generate based on original resolution
        original_resolution = await self._get_video_resolution(metadata.video_id)
        target_qualities = self._select_target_qualities(original_resolution)
        
        # Queue transcoding jobs
        transcoding_jobs = []
        for quality in target_qualities:
            job = {
                'video_id': metadata.video_id,
                'quality': quality,
                'profile': self.quality_profiles[quality],
                'metadata': metadata
            }
            transcoding_jobs.append(job)
            await self.transcoding_queue.put(job)
        
        # Wait for all transcoding jobs to complete
        variants = []
        for _ in transcoding_jobs:
            variant = await self._wait_for_transcoding_result(metadata.video_id)
            if variant:
                variants.append(variant)
        
        return variants
    
    async def _transcoding_worker(self):
        """Background worker for transcoding jobs"""
        while True:
            try:
                job = await self.transcoding_queue.get()
                await self._process_transcoding_job(job)
            except Exception as e:
                print(f"Transcoding worker error: {e}")
    
    async def _process_transcoding_job(self, job: Dict):
        """Process individual transcoding job"""
        video_id = job['video_id']
        quality = job['quality']
        profile = job['profile']
        
        print(f"Transcoding {video_id} to {quality.value}")
        
        # Simulate transcoding (in real implementation, use FFmpeg)
        await asyncio.sleep(2)  # Simulate processing time
        
        # Create video variant
        variant = VideoVariant(
            video_id=video_id,
            quality=quality,
            format='mp4',
            file_path=f"videos/{video_id}/{quality.value}.mp4",
            file_size=profile['bitrate'] * 1000,  # Simplified calculation
            bitrate=profile['bitrate'],
            codec='h264',
            resolution=(profile['width'], profile['height'])
        )
        
        # Store transcoded video
        await self._store_variant(variant)
        
        print(f"Completed transcoding {video_id} to {quality.value}")
    
    async def _get_video_resolution(self, video_id: str) -> Tuple[int, int]:
        """Get original video resolution"""
        # In real implementation, this would analyze the video file
        return (1920, 1080)  # Simulate 1080p original
    
    def _select_target_qualities(self, original_resolution: Tuple[int, int]) -> List[VideoQuality]:
        """Select target qualities based on original resolution"""
        width, height = original_resolution
        qualities = []
        
        # Always include lower qualities
        qualities.extend([VideoQuality.Q_144P, VideoQuality.Q_240P, VideoQuality.Q_360P])
        
        if height >= 480:
            qualities.append(VideoQuality.Q_480P)
        if height >= 720:
            qualities.append(VideoQuality.Q_720P)
        if height >= 1080:
            qualities.append(VideoQuality.Q_1080P)
        if height >= 1440:
            qualities.append(VideoQuality.Q_1440P)
        if height >= 2160:
            qualities.append(VideoQuality.Q_2160P)
        
        return qualities
    
    async def _store_variant(self, variant: VideoVariant):
        """Store transcoded video variant"""
        # In real implementation, store in CDN-backed storage
        print(f"Storing variant: {variant.file_path}")
    
    async def _wait_for_transcoding_result(self, video_id: str) -> Optional[VideoVariant]:
        """Wait for transcoding result (simplified)"""
        # In real implementation, this would wait for actual completion
        await asyncio.sleep(1)
        return None  # Simplified for demo

class VideoRecommendationEngine:
    """Handles video recommendations and personalization"""
    
    def __init__(self):
        self.user_preferences: Dict[str, Dict] = {}
        self.video_features: Dict[str, Dict] = {}
        self.trending_videos: List[str] = []
    
    async def get_recommendations(self, user_id: str, count: int = 20) -> List[str]:
        """Get personalized video recommendations"""
        user_prefs = self.user_preferences.get(user_id, {})
        
        if not user_prefs:
            # New user - return trending videos
            return self.trending_videos[:count]
        
        # Get recommendations based on user history
        recommendations = await self._calculate_recommendations(user_id, user_prefs)
        
        # Mix with trending content
        trending_mix = self.trending_videos[:count // 4]
        recommendations = recommendations[:count - len(trending_mix)] + trending_mix
        
        return recommendations
    
    async def _calculate_recommendations(self, user_id: str, preferences: Dict) -> List[str]:
        """Calculate personalized recommendations"""
        # Simplified recommendation algorithm
        # In real implementation, this would use ML models
        
        favorite_categories = preferences.get('categories', [])
        watched_videos = preferences.get('watched', [])
        
        recommendations = []
        
        # Find similar videos to watched ones
        for video_id in watched_videos[-10:]:  # Last 10 watched
            similar_videos = await self._find_similar_videos(video_id)
            recommendations.extend(similar_videos[:5])
        
        # Add videos from favorite categories
        for category in favorite_categories:
            category_videos = await self._get_videos_by_category(category)
            recommendations.extend(category_videos[:10])
        
        # Remove duplicates and already watched
        recommendations = list(set(recommendations))
        recommendations = [v for v in recommendations if v not in watched_videos]
        
        return recommendations[:50]
    
    async def _find_similar_videos(self, video_id: str) -> List[str]:
        """Find videos similar to given video"""
        # Simplified similarity calculation
        return [f"similar_{video_id}_{i}" for i in range(10)]
    
    async def _get_videos_by_category(self, category: str) -> List[str]:
        """Get videos from specific category"""
        # Simplified category lookup
        return [f"category_{category}_{i}" for i in range(20)]
    
    async def update_user_interaction(self, user_id: str, video_id: str, 
                                    interaction_type: str, duration: float = 0):
        """Update user preferences based on interaction"""
        if user_id not in self.user_preferences:
            self.user_preferences[user_id] = {
                'watched': [],
                'liked': [],
                'categories': [],
                'watch_time': 0
            }
        
        prefs = self.user_preferences[user_id]
        
        if interaction_type == 'watch':
            prefs['watched'].append(video_id)
            prefs['watch_time'] += duration
            
            # Keep only recent history
            if len(prefs['watched']) > 1000:
                prefs['watched'] = prefs['watched'][-1000:]
        
        elif interaction_type == 'like':
            prefs['liked'].append(video_id)
        
        # Update trending videos based on global interactions
        await self._update_trending(video_id, interaction_type)
    
    async def _update_trending(self, video_id: str, interaction_type: str):
        """Update trending videos list"""
        # Simplified trending calculation
        if video_id not in self.trending_videos:
            self.trending_videos.append(video_id)
        
        # Keep trending list manageable
        if len(self.trending_videos) > 100:
            self.trending_videos = self.trending_videos[-100:]

class YouTubeSystem:
    """Main YouTube system coordinator"""
    
    def __init__(self):
        self.upload_handler = VideoUploadHandler(None)
        self.transcoder = VideoTranscoder()
        self.recommendation_engine = VideoRecommendationEngine()
        self.video_metadata: Dict[str, VideoMetadata] = {}
        self.video_variants: Dict[str, List[VideoVariant]] = {}
    
    async def upload_video(self, metadata: VideoMetadata) -> str:
        """Handle complete video upload process"""
        # Store metadata
        self.video_metadata[metadata.video_id] = metadata
        
        # Initiate upload
        upload_id = await self.upload_handler.initiate_upload(metadata)
        
        return upload_id
    
    async def process_uploaded_video(self, video_id: str):
        """Process uploaded video through transcoding pipeline"""
        metadata = self.video_metadata[video_id]
        
        # Transcode to multiple qualities
        variants = await self.transcoder.transcode_video(metadata)
        self.video_variants[video_id] = variants
        
        # Update status to ready
        metadata.status = VideoStatus.READY
        
        print(f"Video {video_id} processing complete")
    
    async def get_video_for_playback(self, video_id: str, 
                                   quality: VideoQuality) -> Optional[VideoVariant]:
        """Get video variant for playback"""
        variants = self.video_variants.get(video_id, [])
        
        # Find requested quality or best available
        for variant in variants:
            if variant.quality == quality:
                return variant
        
        # Fallback to highest available quality
        if variants:
            return max(variants, key=lambda v: int(v.quality.value[:-1]))
        
        return None
    
    async def get_recommendations(self, user_id: str) -> List[str]:
        """Get video recommendations for user"""
        return await self.recommendation_engine.get_recommendations(user_id)
    
    async def record_view(self, user_id: str, video_id: str, watch_duration: float):
        """Record video view and update analytics"""
        # Update video metadata
        if video_id in self.video_metadata:
            self.video_metadata[video_id].view_count += 1
        
        # Update user preferences
        await self.recommendation_engine.update_user_interaction(
            user_id, video_id, 'watch', watch_duration
        )
    
    def get_system_stats(self) -> Dict:
        """Get system statistics"""
        total_videos = len(self.video_metadata)
        ready_videos = len([v for v in self.video_metadata.values() 
                           if v.status == VideoStatus.READY])
        total_views = sum(v.view_count for v in self.video_metadata.values())
        
        return {
            'total_videos': total_videos,
            'ready_videos': ready_videos,
            'processing_videos': total_videos - ready_videos,
            'total_views': total_views,
            'total_variants': sum(len(variants) for variants in self.video_variants.values())
        }

Key Design Decisions

1. Global CDN Infrastructure:

  • Edge Servers: 1000+ locations worldwide
  • Adaptive Bitrate: Dynamic quality adjustment
  • Caching Strategy: Popular content cached globally
  • Regional Storage: Content stored near users

2. Massive Storage System:

  • Bigtable: Metadata storage
  • Colossus: Distributed file system
  • Multiple Replicas: Redundancy across data centers
  • Automatic Tiering: Hot/warm/cold storage

3. Machine Learning Pipeline:

  • Recommendation Engine: Personalized content discovery
  • Content Analysis: Automatic categorization
  • Abuse Detection: Automated content moderation
  • Trending Algorithm: Real-time popularity tracking

Uber Architecture

System Overview

Uber Scale:

  • 100+ million monthly active users
  • 15+ million trips per day
  • 5+ million drivers
  • 700+ cities worldwide

Architecture Design

High-Level Architecture:

[Mobile Apps] → [API Gateway] → [Microservices] → [Databases]
      ↓              ↓              ↓              ↓
[Real-time Location] → [Matching Engine] → [Trip Management] → [Payment]

Core Services Implementation (Python)

python
import asyncio
import time
import math
import json
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass, asdict
from enum import Enum
import redis
from geopy.distance import geodesic
import heapq

class TripStatus(Enum):
    REQUESTED = "requested"
    MATCHED = "matched"
    ACCEPTED = "accepted"
    DRIVER_ARRIVING = "driver_arriving"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    CANCELLED = "cancelled"

class DriverStatus(Enum):
    OFFLINE = "offline"
    ONLINE = "online"
    BUSY = "busy"
    ARRIVING = "arriving"

class VehicleType(Enum):
    UBER_X = "uberx"
    UBER_XL = "uberxl"
    UBER_BLACK = "uberblack"
    UBER_POOL = "uberpool"

@dataclass
class Location:
    latitude: float
    longitude: float
    timestamp: float = None
    
    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = time.time()
    
    def distance_to(self, other: 'Location') -> float:
        """Calculate distance in kilometers"""
        return geodesic((self.latitude, self.longitude), 
                       (other.latitude, other.longitude)).kilometers

@dataclass
class Driver:
    driver_id: str
    name: str
    phone: str
    vehicle_type: VehicleType
    license_plate: str
    rating: float
    status: DriverStatus
    current_location: Location
    last_updated: float
    total_trips: int = 0
    earnings_today: float = 0.0

@dataclass
class Rider:
    rider_id: str
    name: str
    phone: str
    rating: float
    payment_methods: List[str]
    current_location: Optional[Location] = None

@dataclass
class TripRequest:
    request_id: str
    rider_id: str
    pickup_location: Location
    destination_location: Location
    vehicle_type: VehicleType
    requested_at: float
    estimated_fare: float
    status: TripStatus = TripStatus.REQUESTED
    matched_driver_id: Optional[str] = None
    estimated_arrival_time: Optional[float] = None
    estimated_trip_duration: Optional[float] = None

@dataclass
class Trip:
    trip_id: str
    request_id: str
    rider_id: str
    driver_id: str
    pickup_location: Location
    destination_location: Location
    vehicle_type: VehicleType
    status: TripStatus
    created_at: float
    started_at: Optional[float] = None
    completed_at: Optional[float] = None
    fare: Optional[float] = None
    distance_km: Optional[float] = None
    duration_minutes: Optional[float] = None
    driver_rating: Optional[float] = None
    rider_rating: Optional[float] = None

class LocationService:
    """Manages real-time location tracking"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.location_updates = asyncio.Queue()
        
        # Start location processing task
        asyncio.create_task(self._process_location_updates())
    
    async def update_driver_location(self, driver_id: str, location: Location):
        """Update driver's real-time location"""
        # Store in Redis with geospatial indexing
        await self.redis.geoadd(
            'driver_locations',
            location.longitude,
            location.latitude,
            driver_id
        )
        
        # Store detailed location data
        location_key = f"driver_location:{driver_id}"
        await self.redis.hset(location_key, mapping={
            'latitude': location.latitude,
            'longitude': location.longitude,
            'timestamp': location.timestamp
        })
        await self.redis.expire(location_key, 300)  # 5 minutes TTL
        
        # Queue for real-time processing
        await self.location_updates.put({
            'driver_id': driver_id,
            'location': location,
            'type': 'driver_update'
        })
    
    async def update_rider_location(self, rider_id: str, location: Location):
        """Update rider's location"""
        location_key = f"rider_location:{rider_id}"
        await self.redis.hset(location_key, mapping={
            'latitude': location.latitude,
            'longitude': location.longitude,
            'timestamp': location.timestamp
        })
        await self.redis.expire(location_key, 300)
    
    async def find_nearby_drivers(self, location: Location, radius_km: float = 5.0,
                                vehicle_type: VehicleType = None) -> List[Tuple[str, float]]:
        """Find drivers within radius of location"""
        # Use Redis GEORADIUS for efficient spatial queries
        nearby_drivers = await self.redis.georadius(
            'driver_locations',
            location.longitude,
            location.latitude,
            radius_km,
            unit='km',
            withdist=True,
            sort='ASC'
        )
        
        # Filter by vehicle type if specified
        if vehicle_type:
            filtered_drivers = []
            for driver_id, distance in nearby_drivers:
                driver_info = await self._get_driver_info(driver_id)
                if driver_info and driver_info.get('vehicle_type') == vehicle_type.value:
                    filtered_drivers.append((driver_id, distance))
            return filtered_drivers
        
        return nearby_drivers
    
    async def _get_driver_info(self, driver_id: str) -> Optional[Dict]:
        """Get driver information from cache"""
        driver_key = f"driver:{driver_id}"
        return await self.redis.hgetall(driver_key)
    
    async def _process_location_updates(self):
        """Process real-time location updates"""
        while True:
            try:
                update = await self.location_updates.get()
                await self._handle_location_update(update)
            except Exception as e:
                print(f"Error processing location update: {e}")
    
    async def _handle_location_update(self, update: Dict):
        """Handle individual location update"""
        if update['type'] == 'driver_update':
            # Update any active trips
            driver_id = update['driver_id']
            location = update['location']
            
            # Check if driver has active trip
            active_trip = await self._get_active_trip_for_driver(driver_id)
            if active_trip:
                await self._update_trip_location(active_trip, location)
    
    async def _get_active_trip_for_driver(self, driver_id: str) -> Optional[str]:
        """Get active trip ID for driver"""
        trip_key = f"driver_active_trip:{driver_id}"
        return await self.redis.get(trip_key)
    
    async def _update_trip_location(self, trip_id: str, location: Location):
        """Update trip with current driver location"""
        trip_location_key = f"trip_location:{trip_id}"
        await self.redis.hset(trip_location_key, mapping={
            'latitude': location.latitude,
            'longitude': location.longitude,
            'timestamp': location.timestamp
        })

class MatchingEngine:
    """Handles driver-rider matching algorithm"""
    
    def __init__(self, location_service: LocationService):
        self.location_service = location_service
        self.pending_requests: Dict[str, TripRequest] = {}
        self.matching_queue = asyncio.Queue()
        
        # Start matching worker
        asyncio.create_task(self._matching_worker())
    
    async def request_ride(self, trip_request: TripRequest) -> str:
        """Process new ride request"""
        self.pending_requests[trip_request.request_id] = trip_request
        
        # Add to matching queue
        await self.matching_queue.put(trip_request)
        
        return trip_request.request_id
    
    async def _matching_worker(self):
        """Background worker for matching requests"""
        while True:
            try:
                request = await self.matching_queue.get()
                await self._process_matching_request(request)
            except Exception as e:
                print(f"Matching worker error: {e}")
    
    async def _process_matching_request(self, request: TripRequest):
        """Process individual matching request"""
        # Find nearby available drivers
        nearby_drivers = await self.location_service.find_nearby_drivers(
            request.pickup_location,
            radius_km=10.0,
            vehicle_type=request.vehicle_type
        )
        
        if not nearby_drivers:
            # No drivers available, keep in queue for retry
            await asyncio.sleep(5)
            await self.matching_queue.put(request)
            return
        
        # Score and rank drivers
        driver_scores = await self._score_drivers(request, nearby_drivers)
        
        # Try to match with best drivers in order
        for driver_id, score in driver_scores:
            if await self._attempt_match(request, driver_id):
                break
        else:
            # No successful match, retry later
            await asyncio.sleep(10)
            await self.matching_queue.put(request)
    
    async def _score_drivers(self, request: TripRequest, 
                           nearby_drivers: List[Tuple[str, float]]) -> List[Tuple[str, float]]:
        """Score and rank drivers for matching"""
        scored_drivers = []
        
        for driver_id, distance in nearby_drivers:
            # Get driver details
            driver_info = await self.location_service._get_driver_info(driver_id)
            if not driver_info or driver_info.get('status') != DriverStatus.ONLINE.value:
                continue
            
            # Calculate score based on multiple factors
            score = await self._calculate_driver_score(
                driver_id, distance, driver_info, request
            )
            
            scored_drivers.append((driver_id, score))
        
        # Sort by score (higher is better)
        scored_drivers.sort(key=lambda x: x[1], reverse=True)
        
        return scored_drivers[:5]  # Top 5 candidates
    
    async def _calculate_driver_score(self, driver_id: str, distance: float,
                                    driver_info: Dict, request: TripRequest) -> float:
        """Calculate driver matching score"""
        # Base score starts at 100
        score = 100.0
        
        # Distance factor (closer is better)
        score -= distance * 2  # Penalty for distance
        
        # Driver rating factor
        rating = float(driver_info.get('rating', 4.0))
        score += (rating - 4.0) * 10  # Bonus for high rating
        
        # Driver acceptance rate (if available)
        acceptance_rate = float(driver_info.get('acceptance_rate', 0.8))
        score += acceptance_rate * 20
        
        # Time since last trip (prefer active drivers)
        last_trip_time = float(driver_info.get('last_trip_time', 0))
        if last_trip_time > 0:
            time_since_trip = time.time() - last_trip_time
            if time_since_trip < 3600:  # Within last hour
                score += 10
        
        # Direction factor (if driver is heading towards pickup)
        # This would require more complex calculation in real implementation
        
        return max(0, score)
    
    async def _attempt_match(self, request: TripRequest, driver_id: str) -> bool:
        """Attempt to match request with specific driver"""
        # Send match request to driver
        match_request = {
            'request_id': request.request_id,
            'rider_name': 'Rider',  # Would get from rider service
            'pickup_location': asdict(request.pickup_location),
            'destination_location': asdict(request.destination_location),
            'estimated_fare': request.estimated_fare,
            'estimated_distance': request.pickup_location.distance_to(request.destination_location)
        }
        
        # In real implementation, this would send push notification to driver
        print(f"Sending match request to driver {driver_id}: {match_request}")
        
        # Simulate driver response (in real implementation, wait for actual response)
        await asyncio.sleep(1)
        driver_accepted = True  # Simulate acceptance
        
        if driver_accepted:
            # Update request status
            request.status = TripStatus.MATCHED
            request.matched_driver_id = driver_id
            
            # Remove from pending requests
            if request.request_id in self.pending_requests:
                del self.pending_requests[request.request_id]
            
            print(f"Match successful: Request {request.request_id} matched with driver {driver_id}")
            return True
        
        return False

class TripService:
    """Manages trip lifecycle"""
    
    def __init__(self, location_service: LocationService):
        self.location_service = location_service
        self.active_trips: Dict[str, Trip] = {}
        self.trip_history: Dict[str, Trip] = {}
    
    async def create_trip(self, request: TripRequest) -> Trip:
        """Create trip from matched request"""
        trip = Trip(
            trip_id=f"trip_{int(time.time())}_{request.request_id}",
            request_id=request.request_id,
            rider_id=request.rider_id,
            driver_id=request.matched_driver_id,
            pickup_location=request.pickup_location,
            destination_location=request.destination_location,
            vehicle_type=request.vehicle_type,
            status=TripStatus.ACCEPTED,
            created_at=time.time()
        )
        
        self.active_trips[trip.trip_id] = trip
        
        # Estimate arrival time
        await self._calculate_trip_estimates(trip)
        
        return trip
    
    async def update_trip_status(self, trip_id: str, new_status: TripStatus,
                               location: Optional[Location] = None):
        """Update trip status"""
        if trip_id not in self.active_trips:
            return
        
        trip = self.active_trips[trip_id]
        old_status = trip.status
        trip.status = new_status
        
        if new_status == TripStatus.IN_PROGRESS and not trip.started_at:
            trip.started_at = time.time()
        
        elif new_status == TripStatus.COMPLETED:
            trip.completed_at = time.time()
            
            # Calculate final trip metrics
            if trip.started_at:
                trip.duration_minutes = (trip.completed_at - trip.started_at) / 60
            
            # Calculate distance (simplified)
            trip.distance_km = trip.pickup_location.distance_to(trip.destination_location)
            
            # Calculate fare
            trip.fare = await self._calculate_fare(trip)
            
            # Move to history
            self.trip_history[trip_id] = trip
            del self.active_trips[trip_id]
        
        print(f"Trip {trip_id} status updated: {old_status.value} -> {new_status.value}")
    
    async def _calculate_trip_estimates(self, trip: Trip):
        """Calculate trip time and distance estimates"""
        # Get driver's current location
        driver_location_key = f"driver_location:{trip.driver_id}"
        driver_location_data = await self.location_service.redis.hgetall(driver_location_key)
        
        if driver_location_data:
            driver_location = Location(
                latitude=float(driver_location_data['latitude']),
                longitude=float(driver_location_data['longitude'])
            )
            
            # Estimate arrival time (simplified)
            distance_to_pickup = driver_location.distance_to(trip.pickup_location)
            trip.estimated_arrival_time = time.time() + (distance_to_pickup * 2 * 60)  # 2 min per km
            
            # Estimate trip duration
            trip_distance = trip.pickup_location.distance_to(trip.destination_location)
            trip.estimated_trip_duration = trip_distance * 3 * 60  # 3 min per km
    
    async def _calculate_fare(self, trip: Trip) -> float:
        """Calculate trip fare"""
        # Simplified fare calculation
        base_fare = 2.50
        per_km_rate = 1.20
        per_minute_rate = 0.25
        
        distance_fare = trip.distance_km * per_km_rate
        time_fare = trip.duration_minutes * per_minute_rate
        
        # Apply surge pricing if needed
        surge_multiplier = await self._get_surge_multiplier(trip.pickup_location)
        
        total_fare = (base_fare + distance_fare + time_fare) * surge_multiplier
        
        return round(total_fare, 2)
    
    async def _get_surge_multiplier(self, location: Location) -> float:
        """Get surge pricing multiplier for location"""
        # Simplified surge calculation
        # In real implementation, this would consider supply/demand
        return 1.0  # No surge for demo
    
    def get_trip_stats(self) -> Dict:
        """Get trip service statistics"""
        return {
            'active_trips': len(self.active_trips),
            'completed_trips': len(self.trip_history),
            'total_trips': len(self.active_trips) + len(self.trip_history)
        }

class UberSystem:
    """Main Uber system coordinator"""
    
    def __init__(self):
        self.redis = redis.Redis(host='localhost', port=6379, decode_responses=True)
        self.location_service = LocationService(self.redis)
        self.matching_engine = MatchingEngine(self.location_service)
        self.trip_service = TripService(self.location_service)
        
        self.drivers: Dict[str, Driver] = {}
        self.riders: Dict[str, Rider] = {}
    
    async def register_driver(self, driver: Driver):
        """Register new driver"""
        self.drivers[driver.driver_id] = driver
        
        # Store in Redis
        driver_key = f"driver:{driver.driver_id}"
        await self.redis.hset(driver_key, mapping={
            'name': driver.name,
            'vehicle_type': driver.vehicle_type.value,
            'rating': driver.rating,
            'status': driver.status.value
        })
    
    async def register_rider(self, rider: Rider):
        """Register new rider"""
        self.riders[rider.rider_id] = rider
    
    async def driver_goes_online(self, driver_id: str, location: Location):
        """Driver goes online at location"""
        if driver_id in self.drivers:
            self.drivers[driver_id].status = DriverStatus.ONLINE
            self.drivers[driver_id].current_location = location
            
            await self.location_service.update_driver_location(driver_id, location)
    
    async def request_ride(self, rider_id: str, pickup_location: Location,
                         destination_location: Location, vehicle_type: VehicleType) -> str:
        """Request a ride"""
        # Calculate estimated fare
        distance = pickup_location.distance_to(destination_location)
        estimated_fare = 2.50 + (distance * 1.20)  # Simplified calculation
        
        trip_request = TripRequest(
            request_id=f"req_{int(time.time())}_{rider_id}",
            rider_id=rider_id,
            pickup_location=pickup_location,
            destination_location=destination_location,
            vehicle_type=vehicle_type,
            requested_at=time.time(),
            estimated_fare=estimated_fare
        )
        
        request_id = await self.matching_engine.request_ride(trip_request)
        return request_id
    
    async def update_driver_location(self, driver_id: str, location: Location):
        """Update driver's real-time location"""
        if driver_id in self.drivers:
            self.drivers[driver_id].current_location = location
            await self.location_service.update_driver_location(driver_id, location)
    
    def get_system_stats(self) -> Dict:
        """Get system-wide statistics"""
        online_drivers = len([d for d in self.drivers.values() 
                            if d.status == DriverStatus.ONLINE])
        
        trip_stats = self.trip_service.get_trip_stats()
        
        return {
            'total_drivers': len(self.drivers),
            'online_drivers': online_drivers,
            'total_riders': len(self.riders),
            'pending_requests': len(self.matching_engine.pending_requests),
            **trip_stats
        }

Key Design Decisions

1. Real-Time Location Tracking:

  • GPS Updates: Every 4 seconds for drivers
  • Geospatial Indexing: Redis GeoHash for efficient queries
  • Location Prediction: Machine learning for ETA accuracy
  • Battery Optimization: Adaptive update frequency

2. Matching Algorithm:

  • Supply-Demand Balance: Dynamic pricing and incentives
  • Multi-Factor Scoring: Distance, rating, acceptance rate
  • Real-Time Optimization: Continuous algorithm improvement
  • Fairness Mechanisms: Prevent driver cherry-picking

3. Microservices Architecture:

  • Service Isolation: Independent scaling and deployment
  • Event-Driven Communication: Kafka for real-time events
  • Circuit Breakers: Fault tolerance between services
  • API Gateway: Centralized routing and authentication

Netflix Architecture

System Overview

Netflix Scale:

  • 230+ million subscribers globally
  • 15,000+ titles
  • 1+ billion hours watched weekly
  • 190+ countries served

Architecture Design

High-Level Architecture:

[CDN] → [API Gateway] → [Microservices] → [Databases]
  ↓         ↓              ↓              ↓
[Video Encoding] → [Recommendation] → [User Data] → [Analytics]

Recommendation System Implementation (Python)

python
import numpy as np
import pandas as pd
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.decomposition import TruncatedSVD
import redis
import json
from collections import defaultdict

@dataclass
class Content:
    content_id: str
    title: str
    genre: List[str]
    release_year: int
    duration_minutes: int
    rating: str
    language: str
    country: str
    cast: List[str]
    director: str
    description: str
    popularity_score: float
    quality_score: float

@dataclass
class UserProfile:
    user_id: str
    age: int
    country: str
    language: str
    subscription_type: str
    viewing_history: List[str]
    ratings: Dict[str, float]
    genres_preference: Dict[str, float]
    watch_time_by_hour: Dict[int, float]
    device_types: List[str]

@dataclass
class ViewingSession:
    session_id: str
    user_id: str
    content_id: str
    start_time: float
    end_time: Optional[float]
    watch_duration: float
    completion_rate: float
    device_type: str
    quality: str
    paused_count: int
    rewound_count: int
    fast_forwarded: bool

class ContentBasedRecommender:
    """Content-based recommendation using content features"""
    
    def __init__(self):
        self.content_features = {}
        self.content_similarity_matrix = None
        self.feature_weights = {
            'genre': 0.3,
            'cast': 0.2,
            'director': 0.15,
            'language': 0.1,
            'release_year': 0.1,
            'rating': 0.05,
            'popularity': 0.1
        }
    
    def build_content_features(self, contents: List[Content]):
        """Build feature vectors for all content"""
        for content in contents:
            features = self._extract_content_features(content)
            self.content_features[content.content_id] = features
        
        # Build similarity matrix
        self._build_similarity_matrix()
    
    def _extract_content_features(self, content: Content) -> Dict:
        """Extract features from content"""
        return {
            'genres': set(content.genre),
            'cast': set(content.cast[:5]),  # Top 5 cast members
            'director': content.director,
            'language': content.language,
            'release_year_bucket': content.release_year // 10 * 10,  # Decade
            'rating': content.rating,
            'popularity_score': content.popularity_score,
            'quality_score': content.quality_score
        }
    
    def _build_similarity_matrix(self):
        """Build content similarity matrix"""
        content_ids = list(self.content_features.keys())
        n_contents = len(content_ids)
        
        similarity_matrix = np.zeros((n_contents, n_contents))
        
        for i, content_id_1 in enumerate(content_ids):
            for j, content_id_2 in enumerate(content_ids):
                if i != j:
                    similarity = self._calculate_content_similarity(
                        self.content_features[content_id_1],
                        self.content_features[content_id_2]
                    )
                    similarity_matrix[i][j] = similarity
        
        self.content_similarity_matrix = similarity_matrix
        self.content_id_to_index = {cid: i for i, cid in enumerate(content_ids)}
    
    def _calculate_content_similarity(self, features1: Dict, features2: Dict) -> float:
        """Calculate similarity between two content items"""
        similarity = 0.0
        
        # Genre similarity
        genre_jaccard = len(features1['genres'] & features2['genres']) / \
                       len(features1['genres'] | features2['genres'])
        similarity += self.feature_weights['genre'] * genre_jaccard
        
        # Cast similarity
        cast_jaccard = len(features1['cast'] & features2['cast']) / \
                      len(features1['cast'] | features2['cast'])
        similarity += self.feature_weights['cast'] * cast_jaccard
        
        # Director similarity
        director_sim = 1.0 if features1['director'] == features2['director'] else 0.0
        similarity += self.feature_weights['director'] * director_sim
        
        # Language similarity
        language_sim = 1.0 if features1['language'] == features2['language'] else 0.0
        similarity += self.feature_weights['language'] * language_sim
        
        # Release year similarity (closer years = higher similarity)
        year_diff = abs(features1['release_year_bucket'] - features2['release_year_bucket'])
        year_sim = max(0, 1 - year_diff / 50)  # Normalize by 50 years
        similarity += self.feature_weights['release_year'] * year_sim
        
        # Rating similarity
        rating_sim = 1.0 if features1['rating'] == features2['rating'] else 0.5
        similarity += self.feature_weights['rating'] * rating_sim
        
        # Popularity similarity
        pop_diff = abs(features1['popularity_score'] - features2['popularity_score'])
        pop_sim = max(0, 1 - pop_diff)
        similarity += self.feature_weights['popularity'] * pop_sim
        
        return similarity
    
    def get_similar_content(self, content_id: str, n_recommendations: int = 10) -> List[str]:
        """Get similar content recommendations"""
        if content_id not in self.content_id_to_index:
            return []
        
        content_index = self.content_id_to_index[content_id]
        similarities = self.content_similarity_matrix[content_index]
        
        # Get top similar content
        similar_indices = np.argsort(similarities)[::-1][:n_recommendations]
        
        content_ids = list(self.content_id_to_index.keys())
        return [content_ids[i] for i in similar_indices]

class CollaborativeFilteringRecommender:
    """Collaborative filtering using matrix factorization"""
    
    def __init__(self, n_factors: int = 50):
        self.n_factors = n_factors
        self.user_factors = None
        self.item_factors = None
        self.user_to_index = {}
        self.item_to_index = {}
        self.svd_model = TruncatedSVD(n_components=n_factors)
    
    def train(self, user_item_matrix: np.ndarray, user_ids: List[str], item_ids: List[str]):
        """Train collaborative filtering model"""
        self.user_to_index = {uid: i for i, uid in enumerate(user_ids)}
        self.item_to_index = {iid: i for i, iid in enumerate(item_ids)}
        
        # Apply SVD for matrix factorization
        self.user_factors = self.svd_model.fit_transform(user_item_matrix)
        self.item_factors = self.svd_model.components_.T
    
    def predict_rating(self, user_id: str, item_id: str) -> float:
        """Predict user rating for item"""
        if user_id not in self.user_to_index or item_id not in self.item_to_index:
            return 0.0
        
        user_idx = self.user_to_index[user_id]
        item_idx = self.item_to_index[item_id]
        
        prediction = np.dot(self.user_factors[user_idx], self.item_factors[item_idx])
        return max(0, min(5, prediction))  # Clamp between 0 and 5
    
    def get_user_recommendations(self, user_id: str, n_recommendations: int = 10,
                               exclude_seen: List[str] = None) -> List[Tuple[str, float]]:
        """Get recommendations for user"""
        if user_id not in self.user_to_index:
            return []
        
        exclude_seen = exclude_seen or []
        user_idx = self.user_to_index[user_id]
        
        # Calculate predictions for all items
        predictions = []
        for item_id, item_idx in self.item_to_index.items():
            if item_id not in exclude_seen:
                score = np.dot(self.user_factors[user_idx], self.item_factors[item_idx])
                predictions.append((item_id, score))
        
        # Sort by predicted score
        predictions.sort(key=lambda x: x[1], reverse=True)
        
        return predictions[:n_recommendations]

class HybridRecommendationEngine:
    """Hybrid recommendation system combining multiple approaches"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.content_recommender = ContentBasedRecommender()
        self.collaborative_recommender = CollaborativeFilteringRecommender()
        self.user_profiles: Dict[str, UserProfile] = {}
        self.content_catalog: Dict[str, Content] = {}
        self.viewing_sessions: List[ViewingSession] = []
        
        # Recommendation weights
        self.algorithm_weights = {
            'collaborative': 0.4,
            'content_based': 0.3,
            'popularity': 0.15,
            'trending': 0.1,
            'diversity': 0.05
        }
    
    async def initialize(self, contents: List[Content], user_profiles: List[UserProfile]):
        """Initialize recommendation engine"""
        # Store content catalog
        for content in contents:
            self.content_catalog[content.content_id] = content
        
        # Store user profiles
        for profile in user_profiles:
            self.user_profiles[profile.user_id] = profile
        
        # Build content-based features
        self.content_recommender.build_content_features(contents)
        
        # Build collaborative filtering model
        await self._build_collaborative_model()
    
    async def _build_collaborative_model(self):
        """Build collaborative filtering model from user data"""
        # Create user-item matrix from viewing history and ratings
        user_ids = list(self.user_profiles.keys())
        item_ids = list(self.content_catalog.keys())
        
        user_item_matrix = np.zeros((len(user_ids), len(item_ids)))
        
        for i, user_id in enumerate(user_ids):
            profile = self.user_profiles[user_id]
            
            # Use explicit ratings if available
            for item_id, rating in profile.ratings.items():
                if item_id in self.content_catalog:
                    j = item_ids.index(item_id)
                    user_item_matrix[i][j] = rating
            
            # Use implicit feedback from viewing history
            for item_id in profile.viewing_history:
                if item_id in self.content_catalog:
                    j = item_ids.index(item_id)
                    if user_item_matrix[i][j] == 0:  # No explicit rating
                        user_item_matrix[i][j] = 3.0  # Implicit positive feedback
        
        # Train collaborative filtering model
        self.collaborative_recommender.train(user_item_matrix, user_ids, item_ids)
    
    async def get_recommendations(self, user_id: str, n_recommendations: int = 20) -> List[str]:
        """Get hybrid recommendations for user"""
        if user_id not in self.user_profiles:
            return await self._get_popular_content(n_recommendations)
        
        profile = self.user_profiles[user_id]
        
        # Get recommendations from different algorithms
        collaborative_recs = self._get_collaborative_recommendations(user_id, profile)
        content_based_recs = self._get_content_based_recommendations(user_id, profile)
        popularity_recs = await self._get_popularity_recommendations(profile)
        trending_recs = await self._get_trending_recommendations()
        
        # Combine recommendations with weights
        combined_scores = defaultdict(float)
        
        # Collaborative filtering
        for i, (item_id, score) in enumerate(collaborative_recs[:n_recommendations]):
            weight = self.algorithm_weights['collaborative'] * (1 - i / len(collaborative_recs))
            combined_scores[item_id] += weight * score
        
        # Content-based
        for i, item_id in enumerate(content_based_recs[:n_recommendations]):
            weight = self.algorithm_weights['content_based'] * (1 - i / len(content_based_recs))
            combined_scores[item_id] += weight
        
        # Popularity
        for i, item_id in enumerate(popularity_recs[:n_recommendations]):
            weight = self.algorithm_weights['popularity'] * (1 - i / len(popularity_recs))
            combined_scores[item_id] += weight
        
        # Trending
        for i, item_id in enumerate(trending_recs[:n_recommendations]):
            weight = self.algorithm_weights['trending'] * (1 - i / len(trending_recs))
            combined_scores[item_id] += weight
        
        # Apply diversity boost
        await self._apply_diversity_boost(combined_scores, profile)
        
        # Sort by combined score
        recommendations = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True)
        
        # Filter out already watched content
        filtered_recs = [item_id for item_id, _ in recommendations 
                        if item_id not in profile.viewing_history]
        
        return filtered_recs[:n_recommendations]
    
    def _get_collaborative_recommendations(self, user_id: str, profile: UserProfile) -> List[Tuple[str, float]]:
        """Get collaborative filtering recommendations"""
        return self.collaborative_recommender.get_user_recommendations(
            user_id, exclude_seen=profile.viewing_history
        )
    
    def _get_content_based_recommendations(self, user_id: str, profile: UserProfile) -> List[str]:
        """Get content-based recommendations"""
        recommendations = []
        
        # Get similar content to recently watched items
        recent_items = profile.viewing_history[-10:]  # Last 10 watched
        
        for item_id in recent_items:
            similar_items = self.content_recommender.get_similar_content(item_id, 5)
            recommendations.extend(similar_items)
        
        # Remove duplicates while preserving order
        seen = set()
        unique_recs = []
        for item_id in recommendations:
            if item_id not in seen and item_id not in profile.viewing_history:
                seen.add(item_id)
                unique_recs.append(item_id)
        
        return unique_recs
    
    async def _get_popularity_recommendations(self, profile: UserProfile) -> List[str]:
        """Get popular content recommendations"""
        # Filter by user's preferred genres and language
        popular_content = []
        
        for content_id, content in self.content_catalog.items():
            if (content.language == profile.language and
                any(genre in profile.genres_preference for genre in content.genre)):
                popular_content.append((content_id, content.popularity_score))
        
        # Sort by popularity
        popular_content.sort(key=lambda x: x[1], reverse=True)
        
        return [item_id for item_id, _ in popular_content]
    
    async def _get_trending_recommendations(self) -> List[str]:
        """Get trending content"""
        # Get trending content from Redis cache
        trending_key = "trending_content"
        trending_data = await self.redis.get(trending_key)
        
        if trending_data:
            return json.loads(trending_data)
        
        # Fallback to recent popular content
        recent_content = [(cid, content.popularity_score) 
                         for cid, content in self.content_catalog.items() 
                         if content.release_year >= 2020]
        
        recent_content.sort(key=lambda x: x[1], reverse=True)
        trending = [item_id for item_id, _ in recent_content[:50]]
        
        # Cache for 1 hour
        await self.redis.setex(trending_key, 3600, json.dumps(trending))
        
        return trending
    
    async def _apply_diversity_boost(self, scores: Dict[str, float], profile: UserProfile):
        """Apply diversity boost to recommendations"""
        # Boost content from underrepresented genres
        user_genre_counts = defaultdict(int)
        for item_id in profile.viewing_history[-20:]:  # Recent history
            if item_id in self.content_catalog:
                content = self.content_catalog[item_id]
                for genre in content.genre:
                    user_genre_counts[genre] += 1
        
        # Find underrepresented genres
        avg_genre_count = sum(user_genre_counts.values()) / max(len(user_genre_counts), 1)
        
        for item_id in scores:
            if item_id in self.content_catalog:
                content = self.content_catalog[item_id]
                for genre in content.genre:
                    if user_genre_counts[genre] < avg_genre_count * 0.5:
                        scores[item_id] += self.algorithm_weights['diversity']
    
    async def _get_popular_content(self, n_recommendations: int) -> List[str]:
        """Get popular content for new users"""
        popular_content = [(cid, content.popularity_score) 
                          for cid, content in self.content_catalog.items()]
        
        popular_content.sort(key=lambda x: x[1], reverse=True)
        
        return [item_id for item_id, _ in popular_content[:n_recommendations]]
    
    async def record_viewing_session(self, session: ViewingSession):
        """Record user viewing session for learning"""
        self.viewing_sessions.append(session)
        
        # Update user profile
        if session.user_id in self.user_profiles:
            profile = self.user_profiles[session.user_id]
            
            # Add to viewing history if completed significantly
            if session.completion_rate > 0.7:  # Watched more than 70%
                if session.content_id not in profile.viewing_history:
                    profile.viewing_history.append(session.content_id)
            
            # Update genre preferences based on completion rate
            if session.content_id in self.content_catalog:
                content = self.content_catalog[session.content_id]
                for genre in content.genre:
                    current_pref = profile.genres_preference.get(genre, 0.5)
                    # Adjust preference based on completion rate
                    adjustment = (session.completion_rate - 0.5) * 0.1
                    profile.genres_preference[genre] = max(0, min(1, current_pref + adjustment))
        
        # Store session in Redis for analytics
        session_key = f"viewing_session:{session.session_id}"
        await self.redis.setex(session_key, 86400 * 7, json.dumps(session.__dict__))

Key Design Decisions

1. Microservices Architecture:

  • 700+ Microservices: Each with specific responsibilities
  • Service Mesh: Istio for service-to-service communication
  • API Gateway: Zuul for routing and load balancing
  • Circuit Breakers: Hystrix for fault tolerance

2. Global Content Delivery:

  • Open Connect: Custom CDN with 15,000+ servers
  • Regional Caching: Content cached near users
  • Adaptive Streaming: Dynamic quality adjustment
  • Predictive Caching: ML-driven content pre-positioning

3. Data-Driven Personalization:

  • A/B Testing: Continuous experimentation
  • Real-Time Analytics: Immediate feedback loops
  • Machine Learning: Deep learning for recommendations
  • Behavioral Analysis: User interaction patterns

Best Practices from Real-World Systems

Architecture Principles

1. Design for Scale:

  • Horizontal Scaling: Add capacity by adding servers
  • Stateless Services: Enable easy scaling and failover
  • Database Sharding: Distribute data across multiple databases
  • Caching Layers: Reduce database load and improve performance

2. Embrace Failure:

  • Circuit Breakers: Prevent cascading failures
  • Bulkhead Pattern: Isolate critical resources
  • Graceful Degradation: Maintain core functionality during failures
  • Chaos Engineering: Proactively test system resilience

3. Optimize for Performance:

  • CDN Usage: Serve content from edge locations
  • Database Optimization: Proper indexing and query optimization
  • Asynchronous Processing: Non-blocking operations
  • Connection Pooling: Reuse database connections

Technology Choices

1. Database Selection:

  • RDBMS: For ACID transactions and complex queries
  • NoSQL: For high scalability and flexible schemas
  • In-Memory: For caching and real-time data
  • Time-Series: For metrics and monitoring data

2. Communication Patterns:

  • Synchronous: For immediate consistency requirements
  • Asynchronous: For loose coupling and scalability
  • Event Streaming: For real-time data processing
  • Message Queues: For reliable message delivery

3. Monitoring and Observability:

  • Distributed Tracing: Track requests across services
  • Metrics Collection: Monitor system health and performance
  • Centralized Logging: Aggregate logs for analysis
  • Alerting: Proactive notification of issues

Common Pitfalls and Solutions

Scalability Pitfalls

1. Premature Optimization:

  • Problem: Over-engineering before understanding requirements
  • Solution: Start simple, measure, then optimize
  • Example: Don't implement complex caching before identifying bottlenecks

2. Database Bottlenecks:

  • Problem: Single database becomes the limiting factor
  • Solution: Read replicas, sharding, caching
  • Example: WhatsApp's transition from single to sharded databases

3. Synchronous Dependencies:

  • Problem: Services tightly coupled through synchronous calls
  • Solution: Asynchronous messaging, event-driven architecture
  • Example: Netflix's move from synchronous to event-driven communication

Reliability Pitfalls

1. Single Points of Failure:

  • Problem: Critical components without redundancy
  • Solution: Redundancy, load balancing, failover mechanisms
  • Example: Multiple data centers, load balancer redundancy

2. Cascading Failures:

  • Problem: Failure in one service causes failures in dependent services
  • Solution: Circuit breakers, timeouts, bulkhead pattern
  • Example: Netflix's Hystrix preventing cascading failures

3. Data Consistency Issues:

  • Problem: Inconsistent data across distributed systems
  • Solution: Eventual consistency, saga pattern, CQRS
  • Example: Uber's saga pattern for distributed transactions

Performance Pitfalls

1. N+1 Query Problem:

  • Problem: Multiple database queries for related data
  • Solution: Eager loading, data denormalization, caching
  • Example: Loading user profiles with their viewing history

2. Inefficient Caching:

  • Problem: Poor cache hit rates or cache stampede
  • Solution: Proper cache keys, TTL management, cache warming
  • Example: Netflix's predictive caching based on viewing patterns

3. Resource Contention:

  • Problem: Multiple processes competing for limited resources
  • Solution: Connection pooling, rate limiting, resource isolation
  • Example: Database connection limits causing service degradation

Security Pitfalls

1. Insufficient Authentication:

  • Problem: Weak or missing authentication mechanisms
  • Solution: Multi-factor authentication, OAuth 2.0, JWT tokens
  • Example: Secure API access with proper token validation

2. Data Exposure:

  • Problem: Sensitive data exposed through APIs or logs
  • Solution: Data encryption, access controls, log sanitization
  • Example: PII protection in user recommendation systems

3. Injection Attacks:

  • Problem: SQL injection, XSS, and other injection vulnerabilities
  • Solution: Input validation, parameterized queries, output encoding
  • Example: Secure user input handling in search functionality

Key Takeaways

Design Philosophy

1. Start Simple, Scale Smart:

  • Begin with monolithic architecture for rapid development
  • Identify bottlenecks through monitoring and metrics
  • Extract microservices when clear boundaries emerge
  • Scale components independently based on demand

2. Embrace Distributed Systems Complexity:

  • Accept that distributed systems are inherently complex
  • Invest in proper tooling and monitoring
  • Design for failure from the beginning
  • Implement proper testing strategies

3. Data-Driven Decision Making:

  • Measure everything that matters
  • Use A/B testing for feature validation
  • Implement real-time analytics for immediate feedback
  • Make architectural decisions based on data, not assumptions

Evolution Patterns

1. Monolith to Microservices:

  • Phase 1: Monolithic application with clear module boundaries
  • Phase 2: Extract read-heavy services first
  • Phase 3: Decompose based on business capabilities
  • Phase 4: Implement service mesh for communication

2. Database Evolution:

  • Phase 1: Single database with proper indexing
  • Phase 2: Read replicas for scaling reads
  • Phase 3: Sharding for scaling writes
  • Phase 4: Polyglot persistence for different use cases

3. Caching Strategy:

  • Phase 1: Application-level caching
  • Phase 2: Distributed caching layer
  • Phase 3: CDN for static content
  • Phase 4: Intelligent caching with ML

Success Metrics

1. Technical Metrics:

  • Availability: 99.9%+ uptime
  • Latency: P99 response times under acceptable thresholds
  • Throughput: Requests per second capacity
  • Error Rate: Less than 0.1% error rate

2. Business Metrics:

  • User Engagement: Time spent, retention rates
  • Conversion Rates: Sign-ups, purchases, subscriptions
  • Cost Efficiency: Infrastructure cost per user
  • Time to Market: Feature development and deployment speed

3. Operational Metrics:

  • Mean Time to Recovery (MTTR): How quickly issues are resolved
  • Mean Time Between Failures (MTBF): System reliability
  • Deployment Frequency: How often new features are released
  • Change Failure Rate: Percentage of deployments causing issues

Next Chapter: Chapter 15: System Design Interview Preparation


PreviousChapter 19: Testing StrategiesNextChapter 21: System Design Interview Preparation

Open source, free forever. Built by iammhador.

Contribute on GitHub