Curso exprés · No. 09
Escalar no es hacer que todo vaya más rápido — es encontrar la única parte que cede bajo carga y ensancharla, y después la siguiente. La mayoría de los sistemas necesitan mucho menos de esto de lo que sus constructores temen; la habilidad está en saber qué herramienta usar, y cuándo.
Solo la esencia · Una imagen por idea · Medir antes que adivinar
Escalar no es un único interruptor que activás — es el trabajo continuo de manejar más carga sin caerte. Empieza con una sola idea: encontrar la parte que se rompe primero.
Escalar es manejar más sin romperse
Un café chico funciona bien hasta que llega un micro de turistas — de golpe el único barista, la única caja, las pocas mesas no dan abasto. Escalar es prepararse para el micro.
Escalar es manejar el crecimiento — más usuarios, más requests, más datos — manteniéndote rápido y arriba. No se trata de máxima inteligencia; se trata de que el sistema no ceda cuando la carga se multiplica. Y casi todo problema de escalado se reduce a una cosa: algo se convierte en la parte que no da abasto.
Arriba o a los lados: vertical vs horizontal
Para cargar más, podés comprar un camión más grande — solo hasta cierto tamaño — o comprar más camiones: casi sin límite, pero ahora necesitás un despachador.
El escalado vertical es una máquina más grande — más CPU, más RAM. Fácil, pero tiene un techo duro y sigue siendo un único punto de falla. El escalado horizontal son más máquinas trabajando juntas — casi ilimitado, pero necesita coordinación (balanceo de carga, estado compartido). El vertical te compra tiempo; el horizontal es donde vive la escala de verdad.
Todo es una cacería de cuellos de botella
Una autopista es tan rápida como su tramo más angosto — ensanchar cada otro carril no hace nada hasta que arreglás el embudo.
Un sistema es tan rápido como su parte más lenta. Tirar recursos en el lugar equivocado es plata desperdiciada; el trabajo es encontrar el cuello de botella real — la base de datos, un servicio lento, la red — ensancharlo, y después encontrar el siguiente. Escalar es una secuencia de cuellos de botella, no un único arreglo.
La mayoría de los sistemas nunca necesitan mucho de esto
No construís una autopista de seis carriles hacia una cabaña en el bosque. Un buen camino lleva a todos los que la van a visitar.
Un solo servidor decente más una base de datos sirve a una cantidad sorprendente de usuarios. El escalado prematuro — sharding, microservicios, cacheo elaborado antes de tener la carga — es costo y complejidad que no necesitás. Medí primero; escalá lo que realmente está doliendo, cuando realmente duele.
Escalar no es hacer que todo vaya más rápido. Es encontrar el cuello de botella, ensancharlo, y repetir.
Los primeros movimientos reales subiendo la escalera del escalado: superar una sola caja grande, y después hacer que la app pueda correr en tantas cajas idénticas como quieras.
Vertical primero: la caja más grande
Cuando la cocina está desbordada, el primer arreglo es una hornalla más grande y más mesada — no un segundo restaurante.
El escalado más simple es una máquina más grande. No requiere cambios de código y compra margen real rápido — a menudo suficiente por mucho tiempo. Pero tiene un techo duro (no podés comprar un servidor infinito), y esa única caja sigue siendo un único punto de falla. Usalo para comprar tiempo, no como destino.
Horizontal: muchas cajas, un trabajo
Una caja se vuelve diez — ahora se atiende a diez clientes a la vez, y si una caja se traba, las otras nueve siguen.
La escala real significa correr muchas copias de tu app y repartir el trabajo entre ellas. Es casi ilimitado y sobrevive a la pérdida de cualquier máquina. La trampa es la coordinación: algo tiene que repartir los requests (próximo capítulo), y las copias no deben cada una guardar su propio estado privado — que es la siguiente idea, crucial.
Servidores stateless: cualquier caja puede servir cualquier request
Un call center donde cualquier agente puede atender cualquier llamada, porque todos los datos del cliente viven en el sistema compartido — no en la cabeza de un agente.
Para que el escalado horizontal funcione, los servidores de la app deben ser stateless: no guardan nada sobre un usuario entre requests en su propia memoria. Datos de sesión, subidas, progreso — todo vive en algún lugar compartido (una base de datos, una caché, un token que el cliente lleva). Entonces cualquier request puede caer en cualquier servidor, y agregar o perder una caja no cambia nada. El ser stateless es lo que hace que «solo agregá más servidores» realmente funcione.
El vertical compra tiempo; el horizontal compra escala. Y el horizontal solo funciona si tus servidores no recuerdan nada por su cuenta.
Una vez que tenés muchos servidores, algo tiene que pararse al frente y decidir quién maneja cada request. Ese es el balanceador de carga — el policía de tránsito de un sistema escalado.
El balanceador de carga: una puerta de entrada, muchos servidores
Un gestor de filas en un banco que dirige a cada cliente al cajero que esté libre — así ningún cajero queda desbordado mientras otros están ociosos.
Un balanceador de carga (Nginx, HAProxy, un balanceador en la nube) es el único punto de entrada que reparte los requests entrantes entre tu pool de servidores con reglas simples — round-robin, o mandar al menos ocupado. Los clientes le hablan a él, no a servidores individuales, así que podés agregar o quitar máquinas detrás de él de forma invisible. Es lo que convierte una pila de servidores en un solo sistema.
Health checks: dejar de mandar a los muertos
El gestor de filas nota que un cajero se fue y simplemente deja de mandar gente a esa ventanilla — nadie espera frente a un escritorio vacío.
Un balanceador de carga chequea constantemente qué servidores están sanos y rutea esquivando los que no lo están. Una caja caída o sobrecargada se saca de la rotación automáticamente, y el tráfico fluye al resto. Así es como un sistema escalado sobrevive a la muerte de una sola máquina sin que los usuarios lo noten jamás.
Ganancias gratis: deploys sin downtime y failover
Podés renovar un carril de caja a la vez mientras los otros siguen atendiendo — la tienda nunca cierra.
Una vez que el tráfico fluye a través de un balanceador sobre servidores intercambiables, vienen cosas poderosas casi gratis: deploy sin downtime (actualizar servidores de a poco), failover cuando uno muere, y rollback rápido. El balanceador más servidores stateless es la columna vertebral que hace a un sistema escalable y resiliente a la vez.
Un balanceador de carga convierte muchos servidores en una sola dirección — y una máquina muriendo en un no-evento.
El trabajo más rápido es el que no hacés. Antes de escalar las máquinas que hacen el trabajo, recortá cuánto trabajo hay — con cachés y un CDN.
Cacheo: no calcular la misma respuesta dos veces
Un chef que prepara la salsa popular una vez a la mañana, en vez de hacerla desde cero para cada pedido.
Una caché guarda el resultado de un trabajo caro — una query a la base de datos, una página calculada, una llamada a una API — para que el próximo request lo obtenga al instante en vez de rehacerlo. Un store rápido en memoria (Redis, Memcached) frente a la base de datos puede absorber el grueso de las lecturas. A menudo una caché, no más servidores, es lo que tu base de datos sobrecargada realmente necesita.
El CDN: servir a los usuarios desde cerca
Una cadena global que tiene los mismos productos en depósitos locales en todos lados — así los clientes los reciben desde la vuelta de la esquina, no enviados cruzando un océano.
Un CDN mantiene copias de tu contenido estático — imágenes, scripts, video, cada vez más páginas enteras — en data centers alrededor del mundo, sirviendo a cada usuario desde el más cercano. Recorta la latencia y le saca enorme carga a tu origin. Para cualquier cosa global y estática, el CDN hace el trabajo pesado antes de que tus servidores siquiera vean el request.
La parte difícil es la invalidación
El calendario en la heladera es más rápido que mirar el teléfono — hasta que alguien cambia el plan en el teléfono, y ahora la heladera está mintiendo.
Una caché es una segunda copia de la verdad, y una copia puede quedar vieja. La pregunta genuinamente difícil no es agregar una caché — es saber cuándo tirarla para que los usuarios no vean datos viejos. Cacheá lo que se lee mucho más de lo que se escribe, poné expiraciones sensatas, y siempre sabé qué pasa cuando la caché está equivocada. (La misma lección que una caché de base de datos.)
El request más barato es el que nunca servís. Cacheá lo caliente, mandá lo estático desde el edge, y sudá la invalidación.
Tarde o temprano la base de datos se vuelve el cuello de botella — es la única parte genuinamente difícil de escalar, porque contiene la verdad que todos comparten.
La base de datos suele ser el muro
Diez cajas metiendo mano en el mismo único depósito — los cajeros escalan, pero la única puerta del depósito se vuelve el atasco.
Podés correr cien servidores de app stateless, pero normalmente comparten una base de datos — y esa se vuelve el límite. A diferencia de los servidores de app, no podés simplemente clonarla, porque cada copia tiene que estar de acuerdo sobre los datos. Así que escalar la base de datos es la parte más difícil y cuidadosa de escalar un sistema — y la que hay que posponer con cacheo todo lo que puedas.
Read replicas: copiar para lecturas
Repartir fotocopias del libro de referencia para que muchos puedan leer a la vez, mientras la única copia maestra es la única en la que alguien escribe.
La mayoría de las apps leen mucho más de lo que escriben. Las read replicas son copias de la base de datos que sirven queries de lectura, repartiendo esa carga entre máquinas mientras las escrituras siguen yendo a un solo primary. Es el primer y más fácil movimiento para escalar la base de datos — pero las copias quedan ligeramente atrasadas respecto del primary, así que un valor recién escrito puede no aparecer al instante en una replica.
Sharding: dividir las escrituras
Un libro contable desbordado se vuelve varios — A–M en un libro, N–Z en otro — así dos empleados pueden escribir a la vez sin pelear por una sola página.
Cuando hasta las escrituras superan a una sola máquina, hacés sharding: dividís los datos entre varias bases de datos por alguna clave, para que cada una maneje una porción. Desbloquea una escala enorme pero es genuinamente difícil — las queries entre shards se vuelven dolorosas, y la shard key es una elección casi permanente. Este es el extremo profundo; llegá a él al final, cuando las replicas y el cacheo de verdad no alcancen.
Los servidores de app se clonan fácil; la base de datos no. Cacheá y replicá por mucho tiempo antes de hacer sharding.
No todo el trabajo tiene que pasar mientras el usuario espera. Empujar el trabajo lento fuera del request, y poner buffers entre las partes, es cómo un sistema se mantiene rápido y absorbe picos.
Sacar el trabajo lento del camino del request
En un restaurante toman tu pedido y te sentás — no te hacen quedarte parado en el mostrador hasta que la comida está lista.
Cuando un request dispara algo lento — mandar un email, generar un reporte, procesar una subida — no hagas esperar al usuario por eso. Pasalo a una cola en segundo plano y devolvé de inmediato; un worker hace la parte lenta más tarde. La página queda ágil, y el trabajo pesado pasa a un costado. (La idea de mensajería de los cursos de protocolos y arquitectura.)
Las colas absorben picos
Un embalse entre un río desbordado y el pueblo — la crecida llena el embalse en vez de ahogar las calles, y drena a un ritmo parejo.
Una cola es además un buffer. Cuando el tráfico de golpe pega un pico — un lanzamiento, un momento viral — el trabajo se acumula en la cola y los workers la drenan a su propio ritmo, en vez de que una inundación tire abajo el sistema. Sin ese buffer, una crecida que llega más rápido de lo que podés procesar lo derrumba todo. La cola convierte un pico mortal en un backlog manejable.
Desacoplar para que una parte lenta no hunda al resto
Compartimentos estancos en un barco — si uno se inunda, los mamparos mantienen los otros secos y el barco a flote.
Cuando los servicios se hablan a través de colas y eventos en vez de llamadas directas y bloqueantes, un componente lento o caído no congela a todos los que esperaban por él. El pedido igual se toma aunque el servicio de email esté caído; simplemente se pone al día más tarde. El desacoplamiento es lo que permite que un sistema grande se degrade con elegancia bajo estrés en vez de fallar todo de golpe.
Hacé esperar al usuario solo por lo que necesita ahora. Todo lo demás va detrás de una cola — que además te salva cuando pega el pico.
Escalar bien es mayormente contención y orden: medir el cuello de botella real, subir primero los peldaños baratos, y prepararse para las fallas que traen más máquinas.
Medir antes de escalar
Un médico hace estudios antes de operar — cortar en el órgano equivocado porque adivinaste no ayuda a nadie.
Antes de agregar nada, encontrá el cuello de botella real con métricas y profiling — ¿es la base de datos, una query lenta, la red, la CPU? Los ingenieros rutinariamente optimizan lo equivocado porque simplemente se sintió lento. Los datos te dicen dónde duele realmente el sistema; escalá eso, y nada más. (Acá es donde la observabilidad se gana el pan.)
Subí la escalera barata en orden
Ponés aislante y sellás las ventanas antes de comprar una segunda caldera — los arreglos baratos primero.
Hay un orden, lo más barato y fácil primero: una caja más grande, después cacheo y un CDN, después servidores stateless detrás de un balanceador de carga escalando horizontalmente, después read replicas, después colas para el trabajo lento — y solo al final del todo, sharding. Cada peldaño es más trabajo y más complejidad. Subí solo hasta donde tu carga te obligue.
Más máquinas significa más fallas
Una sola lámpara rara vez falla en una noche dada; en un estadio de diez mil, siempre hay varias apagadas. A escala, algo siempre está roto.
A medida que agregás máquinas, la chance de que algo esté fallando en cualquier momento se acerca a la certeza. Así que escalar y confiabilidad son el mismo proyecto: redundancia (sin único punto de falla), health checks y failover, y degradación elegante para que una parte rota suelte calidad en vez de matar el sistema. Diseñá para la falla, porque a escala es constante.
- ¿Medí dónde está el cuello de botella real — y no adiviné? - ¿Hay un peldaño más barato — una caja más grande, una caché, un CDN — antes de este? - ¿Mis servidores de app son stateless, así puedo agregar más? - ¿La carga de la base de datos son lecturas (replicas, caché) o escrituras (el camino difícil)? - ¿Puede el trabajo lento moverse detrás de una cola?
- ¿De verdad tengo esta carga — o estoy construyendo para un futuro que quizás no llegue?
- Sharding de una base de datos que una sola caja podría sostener tranquila. - Microservicios y colas para una app con cien usuarios. - Escalar la parte que no era el cuello de botella, porque se sintió lenta. - Una capa de caché tan enredada que nadie está seguro de cuándo está vieja. - Construir para millones de usuarios que no tenés, y un lanzamiento que no pasó.
- Escalaste el cuello de botella medido, y el siguiente ahora es visible. - Los servidores son stateless; agregar o perder uno es un no-evento. - Las lecturas están cacheadas y replicadas; la base de datos respira. - El trabajo lento corre detrás de colas, y un pico se vuelve un backlog, no un crash. - No hay único punto de falla — cualquier máquina puede morir en silencio. - Subiste solo tan arriba en la escalera como la carga lo requirió.
Escalá el cuello de botella que mediste, con la herramienta más barata que lo arregla, y asumí que a escala algo siempre está roto. Todo lo demás es prematuro.