Módulo 2: Estimación de servilleta (back-of-the-envelope)
8. Proyecto: la tabla de capacidad de Enlace
Descripción
Este es el capstone del módulo: el momento en que dejas de calcular un número a la vez y produces, de cero y tú solo, la tabla de capacidad completa de Enlace. Partiendo únicamente de la escala —los números-ancla del enunciado— vas a derivar los cuatro números de capacidad (QPS, almacenamiento, ancho de banda, memoria), con sus variantes de promedio y pico, con índices y réplicas donde toca, cada cuenta ejecutada en Python, un sanity check por fila, y una nota de supuestos. El entregable es lo que llevarías a una pizarra de diseño o a una entrevista: una tabla defendible que resume, en cinco filas, la capacidad de todo el sistema.
No hay tema nuevo aquí. Todo lo que necesitas lo aprendiste en las lecciones 2 a 7: las herramientas (potencias de 10, segundos por día, unidades), las cuatro cuentas (una por lección), y la disciplina de redondeo y verificación de la lección 7. Este proyecto es el ensamblaje: juntar las piezas en un solo artefacto coherente, con el rigor de que cada número se calcula (no se cita), se redondea con criterio, se cruza con un sanity check, y viene con sus supuestos declarados. Al terminar tendrás la tabla de capacidad de Enlace y —más importante— el método para producir la de cualquier sistema a partir de su escala.
Conexión con el módulo: esta lección cierra el módulo juntando todo. Cada fila de la tabla es una lección: QPS (3), almacenamiento (4), ancho de banda (5), memoria (6); y la disciplina que la vuelve confiable es la lección 7. La tabla que armes aquí es la que Enlace lleva consigo el resto de la guía: en el módulo 3 justificará el modelo de datos y por qué 7 caracteres base62 alcanzan; en el módulo 4, la caché (el working set de 333 MB y el hit ratio); en el módulo 5, la decisión de réplicas y sharding (los 6/27 TB y las 12,000 lecturas/s de pico); en los módulos 6 y 7, el balanceo y los tradeoffs. La frontera del módulo se mantiene hasta el final: aquí estimamos, no diseñamos. La tabla produce los números que las decisiones de diseño usarán; no toma esas decisiones.
El plano de cargas antes de construir
Antes de que un ingeniero estructural levante un edificio, produce una tabla de cargas: cuánto peso soporta cada columna, cuánta fuerza de viento aguanta la fachada, cuánta gente cabe por piso según el código. No es el edificio —no tiene ni una pared dibujada todavía— pero es lo que decide si el edificio es siquiera posible y de qué tamaño deben ser sus vigas. Un plano hecho sin esa tabla es una fantasía bonita que se cae; la tabla de cargas es lo que convierte el dibujo en algo que se puede construir y defender ante el inspector.
La tabla de capacidad es exactamente eso para un sistema. No es el diseño —no tiene cajas ni flechas todavía— pero es lo que dice si el sistema cabe en un servidor o en cien, si la red aguanta, si vale la pena una caché, si hay que repartir la base de datos. Un diseño hecho sin tabla de capacidad es sobreingeniería o subdimensionamiento disfrazados de arquitectura; la tabla es lo que ancla cada decisión posterior a un número que puedes justificar. Por eso este proyecto va al final del módulo de estimación y antes de los módulos de diseño: produces el plano de cargas primero, y con él en la mano, los módulos 3 a 7 dibujan el edificio con criterio.
Y como el ingeniero ante el inspector, la prueba de que tu tabla sirve es que aguanta preguntas. "¿Por qué caché?" → "porque son 4,000 lecturas/s creciendo y el working set cabe en 333 MB de RAM". "¿Por qué no sharding?" → "porque 6 TB caben en un servidor; el QPS lo resuelve la caché". Cada respuesta es una fila de la tabla. Eso es lo que vas a construir.
El encargo
Te dan la escala de Enlace y nada más. Produce la tabla de capacidad completa.
La escala (los números-ancla, idénticos a toda la guía):
- 100 millones de URLs nuevas por mes.
- Ratio lectura:escritura = 100:1.
- Retención: 5 años. URL larga promedio: ~500 bytes; registro completo: ~1 KB.
- Factor de pico a asumir: 3x (dentro del rango 2–3x para servicios web).
Lo que debes entregar:
- La tabla de capacidad, con estas cinco filas, cada número calculado (no citado):
- QPS — escritura y lectura, promedio y pico.
- Almacenamiento — crudo a 5 años, con índices, y aprovisionado con réplicas.
- Ancho de banda — escritura y lectura, promedio y pico; egress mensual.
- Memoria — el working set (20% caliente) y su relación con el total en disco.
- Derivados — servidores para el pico y concurrencia (Ley de Little).
- Una nota de supuestos: cada supuesto que sostiene la tabla (mes de 30 días, factor de pico 3x, índice +50%, réplica ×3, entrada de caché 500 B, etc.).
- Un sanity check por fila: la marca esperada y una referencia que valida el número.
Intenta hacerlo tú antes de mirar la solución. Abre python3, teclea las cuentas, redondea a una cifra significativa, y arma la tabla. La solución completa —con el script ejecutado— está abajo.
Guía: el orden de ensamblaje
Los números se encadenan, así que hay un orden natural que evita recalcular. Síguelo:
- QPS primero, porque casi todo lo demás depende de él. Escritura (100M/mes ÷ segundos/mes), luego lectura (× ratio), luego pico (× factor). Redondea aquí: los números redondeados (40, 4,000) son los que alimentan las filas siguientes.
- Almacenamiento, que no depende del QPS sino del enunciado directo (registros × retención × tamaño), más los factores de índice y réplica.
- Ancho de banda, que reutiliza el QPS (QPS × payload) para escritura y lectura, promedio y pico, más el egress mensual.
- Memoria, que reutiliza las URLs nuevas por día (derivadas del QPS de escritura) para el working set (20% × 500 B).
- Derivados al final: servidores (QPS pico ÷ capacidad por servidor) y concurrencia (Ley de Little).
Con ese orden, cada fila usa números que ya calculaste, y no repites trabajo. Ahora, la solución.
Solución
Ver la solución completa (script ejecutado + tabla + supuestos + sanity checks)
El script que produce toda la tabla
Un solo script, de la escala a los cinco resultados. Puedes pegarlo tal cual en python3:
# TABLA DE CAPACIDAD DE ENLACE — de la escala a los numeros, todo calculado.
# --- NUMEROS-ANCLA (el enunciado, lo unico dado) ---
urls_per_month = 100_000_000 # 100M URLs nuevas/mes
read_write_ratio = 100 # lectura:escritura = 100:1
retention_years = 5 # retencion
url_bytes = 500 # URL larga promedio (payload y entrada de cache)
record_bytes = 1_000 # registro completo ~1 KB (en disco)
peak = 3 # factor de pico (rango 2-3x)
sec_month = 30 * 24 * 3600 # 2,592,000 s/mes
sec_day = 86_400 # s/dia
# --- FILA 1: QPS (se redondea aqui; las filas siguientes parten del redondeado) ---
qps_write = round(urls_per_month / sec_month, -1) # 38.58 -> 40
qps_read = round(qps_write * read_write_ratio, -3) # 4000
print(f"[QPS] escritura ~{qps_write:.0f}/s prom, ~{qps_write*peak:.0f}/s pico | "
f"lectura ~{qps_read:.0f}/s prom, ~{qps_read*peak:.0f}/s pico")
# --- FILA 2: ALMACENAMIENTO (registros x retencion x tamanio, + indices + replicas) ---
records = urls_per_month * 12 * retention_years
raw = records * record_bytes
print(f"[STORAGE] {records/1e9:.0f}e9 registros | crudo {raw/1e12:.0f}TB, "
f"+idx {raw*1.5/1e12:.0f}TB, +repl x3 {raw*1.5*3/1e12:.0f}TB")
# --- FILA 3: ANCHO DE BANDA (QPS x payload) ---
write_bw = qps_write * url_bytes
read_bw = qps_read * url_bytes
egress_month = read_bw * sec_day * 30
print(f"[BANDWIDTH] escritura {write_bw/1e3:.0f}KB/s prom, {write_bw*peak/1e3:.0f}KB/s pico | "
f"lectura {read_bw/1e6:.0f}MB/s prom, {read_bw*peak/1e6:.0f}MB/s pico | egress {egress_month/1e12:.1f}TB/mes")
# --- FILA 4: MEMORIA (working set = 20% caliente de las URLs distintas/dia) ---
new_urls_day = urls_per_month / 30
working_set = new_urls_day * 0.20 * url_bytes
print(f"[MEMORY] WS = 20% x {new_urls_day/1e6:.1f}M URLs/dia x {url_bytes}B = {working_set/1e6:.0f}MB "
f"({raw/working_set:,.0f}x menor que el disco)")
# --- DERIVADOS: servidores (pico / capacidad) y concurrencia (Ley de Little) ---
servers = qps_read * peak / 2000
conc = qps_read * peak * 0.010 # 10 ms por peticion
nic = 1e9 / 8 / 1e6 # NIC de 1 Gbps en MB/s
print(f"[DERIVED] servidores ~{servers:.0f} (+1={servers+1:.0f}) | concurrencia ~{conc:.0f} | "
f"pico lectura = {read_bw*peak/1e6/nic*100:.1f}% de NIC 1Gbps")
Qué esperar.
[QPS] escritura ~40/s prom, ~120/s pico | lectura ~4000/s prom, ~12000/s pico
[STORAGE] 6e9 registros | crudo 6TB, +idx 9TB, +repl x3 27TB
[BANDWIDTH] escritura 20KB/s prom, 60KB/s pico | lectura 2MB/s prom, 6MB/s pico | egress 5.2TB/mes
[MEMORY] WS = 20% x 3.3M URLs/dia x 500B = 333MB (18,000x menor que el disco)
[DERIVED] servidores ~6 (+1=7) | concurrencia ~120 | pico lectura = 4.8% de NIC 1Gbps
La tabla de capacidad de Enlace
Con esos números, la tabla en limpio —el entregable— queda así:
| # | Número | Promedio | Pico (3x) | Con factores | Conclusión de diseño |
|---|---|---|---|---|---|
| 1 | QPS escritura | ~40/s | ~120/s | — | Trivial incluso en pico; una sola BD sobra. |
| 1 | QPS lectura | ~4,000/s | ~12,000/s | — | Read-heavy (100×); pide caché + réplicas. |
| 2 | Almacenamiento | — | — | 6 TB crudo · 9 TB con índices · 27 TB con réplicas ×3 | Cabe en un servidor; no obliga a sharding por espacio. |
| 3 | Ancho de banda escritura | ~20 KB/s | ~60 KB/s | — | Trivial. |
| 3 | Ancho de banda lectura | ~2 MB/s | ~6 MB/s | egress ~5.2 TB/mes | <5% de una NIC de 1 Gbps; la red no es el cuello de botella. |
| 4 | Memoria (working set) | ~333 MB | — | 18,000× menor que el disco | Cabe holgado en RAM; cachear es barato y rentable. |
| — | Derivados | — | — | ~6–7 servidores de app · ~120 conexiones concurrentes | Media docena de máquinas cubren el pico de lectura. |
Siete filas, cada número con su conclusión. Esa densidad —número + qué significa— es lo que distingue una tabla de capacidad útil de una lista de cifras sueltas. Un lector que solo vea la columna de conclusiones ya sabe el carácter entero de Enlace: escritura trivial, lectura pesada, disco manejable, red sobrada, caché rentable, media docena de servidores.
La nota de supuestos
Toda la tabla descansa en supuestos declarados. Sin ellos, los números no son defendibles: cualquiera puede ajustar un supuesto y recalcular. Estos son:
- Tráfico: 100M URLs/mes constantes (sin crecimiento); ratio de lectura 100:1; tráfico promedio, con factor de pico 3x (rango 2–3x para servicios dirigidos a humanos).
- Tiempo: mes de 30 días (2.592×10⁶ s); día de 86,400 s; unidades en base 10 (1 TB = 10¹² B).
- Tamaños: URL larga ~500 B (payload de red y valor de caché); registro completo ~1 KB en disco (con overhead de la BD).
- Almacenamiento: retención de 5 años sin expiración (peor caso de espacio); índices +50%; replicación ×3.
- Memoria: working set = 20% caliente (regla 80/20) de las URLs nuevas por día (~3.3M, proxy del conjunto distinto activo); entrada de caché ~500 B (solo
short_code → long_url); hit ratio esperado ~90%. - Derivados: ~2,000 req/s por servidor de app; ~10 ms por petición (redirección desde caché) para la Ley de Little.
Cada supuesto es una perilla: si el negocio crece a 200M/mes, si las URLs expiran a 2 años, si el pico resulta ser 2x en vez de 3x, se ajusta la perilla y se recalcula. Declarar los supuestos es lo que hace la tabla auditable.
Un sanity check por fila
Antes de entregar, cada número pasa el filtro de la lección 7: cae en su marca esperada y una referencia lo valida.
- QPS escritura (~40/s, marca 10¹): una BD modesta hace miles de inserciones/s → 40/s es trivial. ✓
- QPS lectura (~4,000/s, marca 10³): miles/s es carga real pero lejos de un gigante (millones/s) → pide caché, no maquinaria masiva. ✓
- Almacenamiento (~6 TB, marca 10¹² B): 6×10⁹ registros × 1 KB = 6 TB; cruza con "un SSD es 1–4 TB" → unos pocos discos, cuadra. ✓ Cruce de dos caminos:
6e9 × 1KBy100M × 60 meses × 1KBdan ambos 6 TB. - Ancho de banda lectura (~2 MB/s, marca 10⁶ B/s): una NIC de 1 Gbps son 125 MB/s → 6 MB/s de pico es el 4.8%, trivial. ✓ Cruce:
4,000/s × 500 Byegress diario 173 GB ÷ 86,400 sdan ambos ~2 MB/s. - Memoria (~333 MB, marca 10⁸ B): 0.0056% de los 6 TB en disco, 2% de una RAM de 16 GB → cabe holgado. ✓
- Derivados (~6 servidores): 12,000/s ÷ 2,000/s por servidor = 6; smell test → media docena de máquinas para un acortador de escala media, creíble. ✓
Ninguna fila choca con una capacidad conocida, ninguna cae en una marca absurda, y las relaciones internas son coherentes (lectura = 100× escritura; working set ≪ disco). La tabla aguanta.
La lectura de conjunto
Los números no solo describen capacidad; cuentan una historia de diseño, y saber leerla es la meta del módulo:
Enlace es un sistema read-heavy de escala media. La escritura es un no-problema (40–120/s: una sola base de datos sobra, sin sharding ni colas). Toda la presión está en la lectura (4,000–12,000/s), y la tabla dice exactamente cómo resolverla: el working set de 333 MB cabe en RAM (por eso caché, módulo 4), el disco de 6 TB cabe en un servidor (por eso no hay que shardear por espacio, módulo 5), y el pico se cubre con media docena de servidores de app (por eso balanceo, módulo 6). La red no es el cuello de botella (2–6 MB/s, <5% de una NIC), así que no se gasta esfuerzo ahí. Cada decisión de los módulos siguientes ya está insinuada en una fila de esta tabla. Eso es lo que significa que la estimación precede al diseño: los números dictan el plan, y el diseño lo ejecuta.
Errores comunes
Entregar cifras sin conclusiones (de tabla que no comunica). Qué pasa: alguien produce las cinco filas de números correctos pero se detiene ahí, sin la columna de "qué significa cada uno", y quien la lee tiene los datos pero no el diseño. Por qué pasa: calcular se siente como el trabajo, y traducir el número a una decisión parece un extra. Cómo detectarlo: si tu tabla es una lista de valores sin una conclusión por fila, entregaste la mitad. Cómo corregirlo: cada número termina en una decisión ("~4,000 lecturas/s → pide caché y réplicas"), nunca en sí mismo. La tabla útil no dice "el QPS de lectura es 4,000"; dice "es 4,000, así que caché". El número es el medio; la conclusión es el entregable.
No declarar los supuestos (de tabla que no se puede auditar). Qué pasa: la persona entrega "27 TB" sin decir que asume índices +50%, réplica ×3 y cero expiración, y cuando alguien pregunta "¿y si expiran a 2 años?" no puede responder porque no sabe qué asumió. Por qué pasa: los supuestos se toman por defecto y se olvidan una vez hecha la cuenta. Cómo detectarlo: si no puedes listar de memoria cada perilla que sostiene un número, no lo declaraste. Cómo corregirlo: acompaña la tabla con una nota de supuestos explícita —cada factor, cada redondeo, cada régimen asumido—. Una tabla con supuestos declarados es auditable y ajustable; una sin ellos es un número mágico que se cae con la primera repregunta.
Recalcular en vez de encadenar (de ignorar que los números se alimentan). Qué pasa: alguien vuelve al enunciado para cada fila —divide otra vez 100M entre los segundos, vuelve a estimar las URLs por día desde cero— en vez de reutilizar los números ya calculados, y en el camino introduce inconsistencias (usa 40/s para el ancho de banda pero 38.58/s para la memoria). Por qué pasa: no se ve el grafo de dependencias entre los números. Cómo detectarlo: si el mismo número aparece con dos valores distintos en filas distintas, no encadenaste; recalculaste con redondeos distintos. Cómo corregirlo: sigue el orden de ensamblaje (QPS → todo lo demás), fija el valor redondeado una vez, y aliméntalo a las filas que dependen de él. El ancho de banda y la memoria parten del mismo QPS redondeado que el QPS reporta; así la tabla es internamente consistente.
Ejercicios
Ejercicio 1 — Enlace crece 10×. El producto despega y ahora entran 1,000 millones de URLs/mes (10× la escala original), con todos los demás supuestos iguales. Recalcula la tabla y di, fila por fila, cuáles conclusiones de diseño cambian y cuáles no. En particular: ¿sigue sin necesitar sharding por espacio? ¿La red sigue sobrada?
Ver solución
Con urls_per_month = 1e9, todo escala ~10× (el QPS de escritura redondea a ~400/s):
- QPS: escritura ~400/s (pico ~1,200/s); lectura ~40,000/s (pico ~120,000/s).
- Almacenamiento: 60×10⁹ registros → 60 TB crudo, 90 TB con índices, 270 TB con réplicas ×3.
- Ancho de banda lectura:
40,000/s × 500 B = 20 MB/sprom, 60 MB/s pico. - Memoria (working set):
(1e9/30) × 0.20 × 500 B ≈ 3.33 GB. - Derivados:
120,000 / 2,000 = ~60 servidoresde app.
Qué cambia y qué no:
- Escritura: sigue trivial. 400/s (1,200 pico) lo hace una BD sin problema. La conclusión no cambia.
- Almacenamiento: la conclusión SÍ cambia. 60 TB crudo ya no cabe en un solo servidor (10–20 TB). Ahora el sharding por espacio sí se vuelve necesario —el número cruzó la marca que voltea la decisión—. Este es el ejemplo perfecto de por qué se estima: la misma pregunta ("¿sharding?") da respuesta opuesta al cambiar la escala, y solo el número lo revela.
- Ancho de banda: sigue sobrado, pero ya se vigila. 60 MB/s de pico es el ~48% de una NIC de 1 Gbps —todavía cabe en una NIC, pero ya no es "ignóralo"; con otro 2× o una NIC compartida habría que planear (repartir entre servidores o NIC de 10 Gbps)—. La conclusión pasa de "jamás un problema" a "cómodo pero vigílalo".
- Memoria: sigue cabiendo. 3.33 GB entra holgado en 16 GB de RAM (~20%). Cachear sigue siendo barato.
- Servidores: 60 en vez de 6. Media docena se vuelve varias decenas; el balanceo (módulo 6) se vuelve más central.
La lección del ejercicio: el orden de magnitud de la escala decide el diseño. A 100M/mes Enlace es "un servidor con caché"; a 1,000M/mes es "sharding + decenas de servidores". El método es idéntico —los mismos multiplicadores— pero las conclusiones cruzan marcas y cambian. Por eso un número se calcula y no se cita: sobrevive a "¿y si fuera 10× más grande?".
Ejercicio 2 — La perilla de la expiración. El equipo decide que las URLs expiran a los 2 años en vez de guardarse 5. ¿Qué filas de la tabla cambian y cuáles no? Recalcula el almacenamiento en estado estable y di si esto altera la decisión de sharding.
Ver solución
Con expiración a 2 años, el almacenamiento se estabiliza (deja de crecer sin techo): en cualquier momento solo viven en disco los registros de los últimos 24 meses, porque cada URL nueva reemplaza a una que expira.
- Almacenamiento estable:
100M/mes × 24 meses × 1 KB = 2.4 TB crudo(contra 6 TB a 5 años sin expiración). Con índices: 3.6 TB; con réplicas ×3: ~10.8 TB. - QPS, ancho de banda, memoria: NO cambian. La expiración afecta cuánto se acumula, no el ritmo (QPS), el caudal (ancho de banda) ni la parte caliente (working set, que ya se estimaba sobre las URLs recientes del día). Esas tres filas son idénticas.
¿Cambia el sharding? Lo hace aún menos necesario por espacio: 2.4 TB estable (o 3.6 con índices) cabe con muchísimo margen en un solo servidor, para siempre. La expiración divide el disco entre ~2.5 y elimina el crecimiento indefinido, lo que vuelve el plan de capacidad más cómodo todavía.
La lección: la política de retención es una perilla de diseño con impacto directo en una sola fila (el almacenamiento), y no toca las demás. Un buen estimador sabe qué números mueve cada supuesto —expiración mueve el disco, no el QPS— y por eso puede responder "¿y si expiran a 2 años?" sin rehacer toda la tabla: solo recalcula la fila afectada. Saber qué perilla mueve qué número es parte de tener la tabla "viva".
Ejercicio 3 — Defiende el diseño con la tabla. Un compañero propone, para el Enlace original (100M/mes): "hay que shardear la base de datos en 10 nodos desde el día uno, meter una cola de mensajes para las escrituras, y poner una CDN global para el ancho de banda". Usando solo la tabla de capacidad, argumenta en tres o cuatro frases por qué cada una de esas tres piezas es sobreingeniería para la escala de Enlace, citando el número que la desmiente.
Ver solución
Las tres piezas resuelven problemas que Enlace, a esta escala, no tiene, y la tabla lo prueba número por número:
- Sharding en 10 nodos desde el día uno: innecesario. El almacenamiento es 6 TB crudo (9 con índices), y eso cabe en un solo servidor (un SSD/BD moderno maneja 10–20 TB). El QPS de escritura (40–120/s) es trivial para un solo primario. No hay ni presión de espacio ni de carga de escritura que justifique repartir; shardear en 10 nodos es complejidad cara resolviendo un problema inexistente. (Módulo 5 lo desarrolla.)
- Cola de mensajes para las escrituras: innecesaria. Las colas absorben ráfagas de escritura que la base de datos no puede seguir. Enlace escribe 40/s (120/s en pico), dos órdenes de magnitud por debajo de lo que una BD modesta inserta sin sudar. No hay ráfaga que amortiguar; la escritura va directa a la BD.
- CDN global por ancho de banda: innecesaria (por esa razón). El ancho de banda de lectura es 2 MB/s (6 MB/s pico), menos del 5% de una sola NIC de 1 Gbps. La red no es el cuello de botella, así que una CDN por caudal no aporta nada. (Podría haber otra razón para una CDN —bajar latencia geográfica— pero no el ancho de banda, y el compañero la justificó por ancho de banda.)
El patrón: cada pieza propuesta se cae al confrontarla con la fila correspondiente de la tabla. Lo que Enlace sí necesita —y la tabla también lo dice— es una caché (working set 333 MB, lectura 4,000/s) y quizá réplicas de lectura (módulo 5). La tabla de capacidad es la mejor vacuna contra la sobreingeniería: convierte "por si acaso" en "el número no lo pide", que es un argumento que se puede defender.
Resumen y siguiente paso
En este capstone produjiste, de cero y a partir de la sola escala, la tabla de capacidad completa de Enlace: QPS (~40/~4,000 promedio, ~120/~12,000 pico), almacenamiento (6 TB crudo · 9 con índices · 27 con réplicas), ancho de banda (~2 MB/s lectura, ~5.2 TB/mes de egress), memoria (working set ~333 MB, 18,000× menor que el disco) y derivados (~6–7 servidores, ~120 conexiones concurrentes). Cada número lo calculaste en Python, lo redondeaste a una cifra significativa, lo cruzaste con un sanity check, y lo acompañaste de una nota de supuestos que hace la tabla auditable. Y practicaste lo más importante: leer la tabla como una historia de diseño —escritura trivial, lectura pesada, disco manejable, red sobrada, caché rentable— y usarla para defender qué construir y qué no.
Antes de cerrar el módulo deberías poder: producir la tabla de capacidad de cualquier sistema a partir de su escala, siguiendo el orden de ensamblaje (QPS → todo lo demás); acompañarla de sus supuestos y de un sanity check por fila; recalcularla cuando cambia un supuesto (escala 10×, expiración) sabiendo qué filas se mueven; y usarla para desmontar sobreingeniería con el número que la desmiente.
Con esto cierras el módulo 2. Tienes las herramientas (potencias de 10, unidades), las cuatro cuentas de capacidad, la disciplina de redondeo y verificación, y la tabla que resume todo. Enlace deja de ser un enunciado vago y pasa a ser un sistema con números defendibles. El módulo 3 toma esos números y empieza a diseñar: el modelo de datos del registro Link, SQL contra NoSQL para este caso, y —el corazón— la generación del short_code: hash contra contador+base62 contra random, la función base62_encode/decode, y por qué 7 caracteres base62 alcanzan (62⁷ ≈ 3.5 × 10¹² códigos, de sobra para los 6 mil millones de registros que esta tabla proyectó). La estimación terminó; empieza el diseño, y lo empieza con los números que produjiste aquí en la mano.
Recursos
- The System Design Primer, "Back-of-the-envelope calculations" y el ejercicio del acortador de URLs (Design Pastebin.com / Bit.ly) — github.com/donnemartin/system-design-primer. Recorre una tabla de capacidad casi idéntica a la de Enlace, con la misma estructura de QPS, almacenamiento y ancho de banda. El mejor complemento gratuito para este capstone; en inglés.
- Martin Kleppmann, Designing Data-Intensive Applications, Capítulo 1 ("Reliability, Scalability, and Maintainability") — dataintensive.net. El marco conceptual para describir la carga de un sistema (throughput, percentiles, ratios) que sostiene toda la tabla de capacidad. El libro de cabecera de la guía; en inglés.
- Alex Xu, System Design Interview – An Insider's Guide, capítulo "Back-of-the-envelope estimation" y "Design a URL shortener" — resumen y figuras en bytebytego.com. Presenta la estimación de un acortador de URLs paso a paso, con el mismo espíritu de tabla de capacidad defendible que armamos aquí. En inglés.