06 - Casos de Estudio: Diseño de Sistemas Reales¶
Tabla de Contenidos¶
Metodología de Diseño¶
Antes de abordar cualquier diseño de sistema, sigue estos 4 pasos:
Paso 1: Clarificar Requisitos (5 min)¶
Funcionales: ¿Qué hace el sistema? No funcionales: Escala, latencia, disponibilidad, consistencia
Preguntas clave: - ¿Cuántos usuarios? ¿DAU (daily active users)? - ¿Ratio lectura/escritura? - ¿Qué latencia es aceptable? - ¿Qué disponibilidad se necesita? - ¿Consistencia fuerte o eventual?
Paso 2: Estimaciones de Escala (5 min)¶
Calcular: QPS (queries per second), almacenamiento, ancho de banda.
Paso 3: Diseño de Alto Nivel (15 min)¶
Diagrama de componentes principales y flujos de datos.
Paso 4: Diseño Detallado (15 min)¶
Profundizar en los componentes más críticos o interesantes.
Caso 1: Diseñar Twitter¶
Paso 1: Requisitos¶
Funcionales: - Publicar tweets (280 caracteres + media) - Timeline personal (tweets de las cuentas que sigues) - Buscar tweets - Seguir/dejar de seguir usuarios - Like y retweet
No funcionales: - 500M usuarios, 200M DAU - Un usuario promedio sigue a 200 cuentas - 500M tweets/día (~6000 tweets/seg) - Timeline: lectura pesada (ratio 100:1 read/write) - Latencia de timeline < 200ms - Disponibilidad: 99.99%
Paso 2: Estimaciones¶
Escrituras (tweets):
500M tweets/día = ~6,000 tweets/seg
Tamaño promedio tweet: 280 bytes texto + metadata = ~1 KB
Storage/día: 500M × 1KB = 500 GB/día (solo texto)
Con media (10% con imagen/video): +50M × 500KB = 25 TB/día
Lecturas (timeline):
200M DAU × 5 timeline refreshes/día = 1B requests/día
~12,000 reads/seg
Cada timeline muestra ~200 tweets → data transfer significativo
Relaciones (follows):
200M usuarios × 200 follows promedio = 40B relaciones
Paso 3: Diseño de Alto Nivel¶
graph TD
subgraph "Clientes"
MOB[Mobile App]
WEB[Web App]
end
MOB --> LB[Load Balancer]
WEB --> LB
LB --> GW[API Gateway]
GW --> TS[Tweet Service]
GW --> TLS[Timeline Service]
GW --> US[User Service]
GW --> SS[Search Service]
TS --> TDB[(Tweet Store<br/>MySQL Sharded)]
TS --> MQ[Message Queue<br/>Kafka]
TS --> MEDIA[Media Store<br/>S3 + CDN]
MQ --> FO[Fan-out Service]
FO --> CACHE[(Timeline Cache<br/>Redis Cluster)]
TLS --> CACHE
US --> UDB[(User Store<br/>MySQL)]
US --> GRAPH[(Social Graph<br/>Follow relationships)]
SS --> ES[(Search Index<br/>Elasticsearch)]
TS --> ES
Paso 4: Diseño Detallado¶
El Problema del Fan-out (El Corazón de Twitter)¶
Cuando un usuario publica un tweet, sus seguidores deben verlo en su timeline. Hay dos estrategias:
Fan-out on Write (Push Model)¶
Cuando se publica un tweet, se escribe inmediatamente en el cache de timeline de cada seguidor.
sequenceDiagram
participant User_A as User A (1000 followers)
participant TweetSvc as Tweet Service
participant Kafka
participant FanOut as Fan-out Workers
participant Redis as Timeline Caches
User_A->>TweetSvc: POST /tweet "Hello World"
TweetSvc->>TweetSvc: Guardar en Tweet Store
TweetSvc->>Kafka: Publicar evento TweetCreated
Kafka->>FanOut: Consumir evento
FanOut->>FanOut: Obtener lista de 1000 followers
FanOut->>Redis: LPUSH timeline:follower_1, tweet_id
FanOut->>Redis: LPUSH timeline:follower_2, tweet_id
Note over FanOut,Redis: ... repite para 1000 followers ...
FanOut->>Redis: LPUSH timeline:follower_1000, tweet_id
Ventaja: Lectura de timeline es ultra rápida (solo leer de Redis). Desventaja: Un usuario con 50M de seguidores genera 50M de escrituras. Lento y costoso.
Fan-out on Read (Pull Model)¶
Cuando un usuario abre su timeline, se consultan los tweets recientes de todas las cuentas que sigue.
sequenceDiagram
participant User_B as User B (follows 200 accounts)
participant TimelineSvc as Timeline Service
participant Redis as Tweet Caches
participant TweetDB as Tweet Store
User_B->>TimelineSvc: GET /timeline
TimelineSvc->>TimelineSvc: Obtener lista de 200 followed accounts
TimelineSvc->>Redis: GET tweets de account_1
TimelineSvc->>Redis: GET tweets de account_2
Note over TimelineSvc,Redis: ... 200 queries paralelas ...
TimelineSvc->>TimelineSvc: Merge + Sort por timestamp
TimelineSvc-->>User_B: Top 200 tweets ordenados
Ventaja: Publicar un tweet es instantáneo (solo 1 write). Desventaja: Lectura lenta (200+ queries y merge).
Enfoque Híbrido (Lo que hace Twitter)¶
graph TD
TWEET[Nuevo Tweet] --> CHECK{¿El autor tiene<br/>> 500K followers?}
CHECK -->|No - Usuarios normales| PUSH[Fan-out on Write<br/>Push a timeline caches]
CHECK -->|Sí - Celebridades| PULL[Fan-out on Read<br/>Merge en lectura]
TIMELINE[Request de Timeline] --> MERGE[Merge]
PUSH --> REDIS[(Redis Timeline<br/>Pre-computado)]
REDIS --> MERGE
PULL --> CELEB[(Tweets de celebridades<br/>Query on-the-fly)]
CELEB --> MERGE
MERGE --> USER[Timeline del usuario]
- Usuarios normales (99%): Fan-out on Write (push)
- Celebridades (>500K followers): Fan-out on Read (pull, merge en lectura)
- El timeline final es un merge de ambas fuentes
Tweet Storage: Sharding¶
Shard Key: tweet_id (snowflake ID)
Snowflake ID (64 bits):
| 41 bits: timestamp | 10 bits: machine ID | 12 bits: sequence |
| ~69 años | 1024 máquinas | 4096/ms/máquina |
Ventajas del Snowflake ID: - Ordenable por tiempo (range queries eficientes) - Generado sin coordinación central - Único globalmente
Search: Inverted Index¶
Índice invertido en Elasticsearch:
"hello" → [tweet_1, tweet_45, tweet_892]
"world" → [tweet_1, tweet_203]
"design" → [tweet_45, tweet_567, tweet_892]
Query: "hello world" → intersección → [tweet_1]
Social Graph¶
Las relaciones follow/following se modelan como un grafo dirigido:
Opción 1: Tabla relacional
follows(follower_id, followed_id, created_at)
Índices: (follower_id) para "¿a quién sigo?" y (followed_id) para "¿quién me sigue?"
Opción 2: Graph database (para queries complejas)
"Amigos de amigos que siguen a X"
"Sugerencias basadas en grafo social"
Opción 3: Adjacency list en Redis
followers:user_123 → SET {user_1, user_2, user_3}
following:user_123 → SET {user_50, user_51}
Caso 2: Diseñar Netflix¶
Paso 1: Requisitos¶
Funcionales: - Subir y procesar videos (content team) - Catálogo de contenido con búsqueda - Streaming de video adaptativo (múltiples calidades) - Recomendaciones personalizadas - Perfiles de usuario con historial
No funcionales: - 200M+ suscriptores, 100M DAU - Miles de títulos en el catálogo - Video en múltiples resoluciones (4K, 1080p, 720p, 480p) - Latencia de inicio de playback < 2s - Disponibilidad: 99.99% - Distribución global - Ancho de banda: ~15% del tráfico global de internet
Paso 2: Estimaciones¶
Streaming:
100M DAU × 2 horas/día promedio = 200M horas de video/día
Bitrate promedio: 5 Mbps (1080p)
Ancho de banda pico: ~1 Tbps+
Almacenamiento:
Un título en todos los formatos/resoluciones/idiomas ≈ 1 TB
15,000 títulos × 1 TB = 15 PB
Nuevos títulos: ~100/semana × 1 TB = 100 TB/semana
Catálogo y metadata:
15,000 títulos × 10 KB metadata = 150 MB (cabe en memoria)
Paso 3: Diseño de Alto Nivel¶
graph TD
subgraph "Clientes"
TV[Smart TV]
PHONE[Mobile]
WEB[Browser]
end
subgraph "Content Delivery"
TV --> CDN[CDN / Open Connect<br/>Appliances en ISPs]
PHONE --> CDN
WEB --> CDN
end
subgraph "Control Plane"
TV --> API[API Gateway / Zuul]
API --> CS[Catalog Service]
API --> RS[Recommendation Service]
API --> US[User Service]
API --> PS[Playback Service]
end
subgraph "Content Pipeline"
UPLOAD[Content Upload] --> TRANSCODE[Transcoding Pipeline<br/>Parallel encoding]
TRANSCODE --> QC[Quality Check]
QC --> DIST[Distribution<br/>Push to CDN]
end
subgraph "Data Stores"
CS --> CSDB[(Catalog DB<br/>MySQL + Cache)]
RS --> ML[(ML Models<br/>Feature Store)]
RS --> HIST[(Viewing History<br/>Cassandra)]
US --> UDB[(User DB<br/>MySQL)]
PS --> SESS[(Session Store<br/>Redis)]
end
CDN --> OBJ[(Object Storage<br/>S3)]
Paso 4: Diseño Detallado¶
Video Transcoding Pipeline¶
Un video original debe convertirse a múltiples formatos y resoluciones:
graph LR
ORIG[Video Original<br/>4K ProRes<br/>~500 GB] --> SPLIT[Splitter<br/>Dividir en segmentos<br/>de 5-10 seg]
SPLIT --> T1[Worker 1<br/>Encode 4K H.265]
SPLIT --> T2[Worker 2<br/>Encode 1080p H.264]
SPLIT --> T3[Worker 3<br/>Encode 720p H.264]
SPLIT --> T4[Worker 4<br/>Encode 480p H.264]
SPLIT --> T5[Worker 5<br/>Audio tracks<br/>AAC / Dolby]
T1 --> ASSEMBLE[Assembler]
T2 --> ASSEMBLE
T3 --> ASSEMBLE
T4 --> ASSEMBLE
T5 --> ASSEMBLE
ASSEMBLE --> PACKAGE[Packager<br/>DASH / HLS<br/>Manifest files]
PACKAGE --> S3[S3 Storage]
S3 --> CDN_PUSH[Push to CDN<br/>Worldwide]
Datos clave: - Netflix codifica cada título en ~1200 versiones diferentes (resolución × codec × bitrate × audio) - Usan encoding por escenas: escenas de acción necesitan más bitrate que diálogos - El proceso es masivamente paralelo: cada segmento de 5-10 segundos se codifica independientemente
Adaptive Bitrate Streaming (ABR)¶
El cliente ajusta la calidad del video según las condiciones de red en tiempo real.
sequenceDiagram
participant Client
participant CDN
Client->>CDN: GET /manifest.mpd (DASH)
CDN-->>Client: Lista de segmentos disponibles por calidad
Note over Client: Ancho de banda: 10 Mbps
Client->>CDN: GET /segment_1_4K.mp4
CDN-->>Client: Segmento 4K (8 Mbps)
Note over Client: Red se degrada: 3 Mbps
Client->>CDN: GET /segment_2_720p.mp4
CDN-->>Client: Segmento 720p (2.5 Mbps)
Note over Client: Red se recupera: 8 Mbps
Client->>CDN: GET /segment_3_1080p.mp4
CDN-->>Client: Segmento 1080p (5 Mbps)
Protocolo DASH (Dynamic Adaptive Streaming over HTTP):
<!-- Manifest simplificado (MPD) -->
<AdaptationSet>
<Representation bandwidth="8000000" width="3840" height="2160">
<SegmentList>
<SegmentURL media="4k/segment_1.mp4"/>
<SegmentURL media="4k/segment_2.mp4"/>
</SegmentList>
</Representation>
<Representation bandwidth="5000000" width="1920" height="1080">
<SegmentList>
<SegmentURL media="1080p/segment_1.mp4"/>
<SegmentURL media="1080p/segment_2.mp4"/>
</SegmentList>
</Representation>
</AdaptationSet>
Open Connect: El CDN Propio de Netflix¶
Netflix no depende de CDNs de terceros. Tiene su propia red: Open Connect.
graph TD
subgraph "Netflix Backend (AWS)"
CTRL[Control Plane<br/>API, Auth, Billing]
ORIGIN[Origin<br/>S3 + Encoding]
end
subgraph "Open Connect Network"
ORIGIN -->|Pre-position content<br/>Off-peak hours| OCA1[OCA en ISP 1<br/>Telcel México]
ORIGIN --> OCA2[OCA en ISP 2<br/>Comcast USA]
ORIGIN --> OCA3[OCA en IXP<br/>Amsterdam]
end
subgraph "Usuarios"
U1[Usuario México] -->|Video stream| OCA1
U2[Usuario USA] -->|Video stream| OCA2
U1 -->|API calls| CTRL
end
OCA (Open Connect Appliance): - Servidores físicos instalados directamente en ISPs y IXPs - 100-200 TB de almacenamiento SSD cada uno - Contenido pre-posicionado durante horas de bajo tráfico - ~90% del contenido se sirve desde OCAs locales (1 hop de red) - Netflix da los servidores gratis a los ISPs (ambos se benefician)
Sistema de Recomendaciones (Simplificado)¶
graph TD
subgraph "Datos de Entrada"
VH[Viewing History]
RATINGS[Ratings / Thumbs]
BROWSE[Browsing Behavior]
META[Content Metadata<br/>Género, actores, tags]
DEMO[Demographics]
end
subgraph "Pipeline ML"
VH --> FE[Feature Engineering<br/>Spark]
RATINGS --> FE
BROWSE --> FE
META --> FE
DEMO --> FE
FE --> CF[Collaborative Filtering<br/>Usuarios similares]
FE --> CB[Content-Based<br/>Contenido similar]
CF --> ENSEMBLE[Ensemble Model<br/>Ranking final]
CB --> ENSEMBLE
end
subgraph "Serving"
ENSEMBLE -->|Offline: batch scoring| PRECOMP[(Precomputed Recs<br/>Cassandra)]
ENSEMBLE -->|Online: real-time| ONLINE[Online Model<br/>Feature Store + Redis]
PRECOMP --> ROW[Rows de Homepage<br/>Para cada usuario]
ONLINE --> ROW
end
Datos interesantes: - Netflix estima que su sistema de recomendaciones vale $1B/año en retención de usuarios - ~80% del contenido consumido viene de recomendaciones, no de búsqueda - El artwork (thumbnail) de cada título es personalizado por usuario
Resiliencia: Chaos Engineering¶
Netflix es pionera en Chaos Engineering con herramientas como:
| Herramienta | Qué hace |
|---|---|
| Chaos Monkey | Mata instancias EC2 al azar en producción |
| Chaos Kong | Simula la caída de una región AWS completa |
| Latency Monkey | Inyecta latencia artificial en llamadas entre servicios |
| FIT (Failure Injection Testing) | Fuerza fallos en servicios específicos |
Esto garantiza que cada servicio esté diseñado para sobrevivir fallos inesperados.
Otros Sistemas para Practicar¶
Una vez domines Twitter y Netflix, practica diseñando:
| Sistema | Conceptos Clave |
|---|---|
| URL Shortener (TinyURL) | Hashing, base62, read-heavy, cache |
| Chat (WhatsApp) | WebSockets, presence, message delivery, E2E encryption |
| File Storage (Dropbox) | Chunking, dedup, sync, conflict resolution |
| Search Engine (Google) | Web crawling, inverted index, PageRank, distributed computing |
| Ride Sharing (Uber) | Geospatial index, matching, real-time tracking, ETA |
| Payment System (Stripe) | Idempotency, exactly-once, ledger, PCI compliance |
| Notification System | Multi-channel, rate limiting, priority queues, templates |
| Rate Limiter | Token bucket, sliding window, distributed rate limiting |
Recursos Recomendados¶
- Libro: System Design Interview Vol. 1 y 2 - Alex Xu (ByteByteGo)
- Libro: Designing Data-Intensive Applications - Martin Kleppmann
- Blog: Netflix Tech Blog (netflixtechblog.com)
- Blog: Twitter Engineering Blog
- Paper: "Scaling Memcache at Facebook" - Nishtala et al.
- Paper: "TAO: Facebook's Distributed Data Store for the Social Graph"
- Video: Gaurav Sen - System Design series (YouTube)
- Video: ByteByteGo - System Design Interview series (YouTube)
- Práctica: interviewing.io - Mock interviews
- Práctica: designgurus.org - Grokking System Design