La arquitectura serverless (sin servidor) es un modelo en el que escribes y despliegas código sin gestionar ni aprovisionar servidores: el proveedor cloud se encarga por completo de la infraestructura, ejecuta tu código solo cuando hace falta y te cobra únicamente por el tiempo de ejecución real, normalmente en milisegundos. El nombre engaña: claro que hay servidores, pero tú no los ves ni los administras. Su máxima expresión es FaaS (Funciones como Servicio), donde despliegas funciones pequeñas que reaccionan a eventos. Es relevante porque permite construir sistemas que escalan automáticamente de cero a miles de ejecuciones, con coste cero cuando no hay tráfico, y reduce drásticamente la carga operativa. Pero no es una bala de plata: tiene limitaciones importantes (el cold start, los tiempos máximos de ejecución, la dependencia del proveedor) que debes conocer para decidir cuándo aplicarlo.
Contenido
- Qué es serverless y qué es FaaS.
- Arquitectura dirigida por eventos.
- El problema del cold start (arranque en frío).
- Ventajas y limitaciones.
- Ejemplo de función serverless.
- Cuándo usar serverless y cuándo no.
- Errores comunes y consejos.
- Ejercicios y soluciones.
- Qué es serverless y qué es FaaS
"Serverless" es un paraguas que incluye varios tipos de servicios gestionados que escalan solos y se pagan por uso: bases de datos serverless, colas de mensajes, almacenamiento de objetos, etc. Su componente más representativo es FaaS (Function as a Service): subes una función —una unidad de código pequeña y sin estado— y el proveedor la ejecuta en respuesta a un evento (una petición HTTP, un fichero subido, un mensaje en una cola, un temporizador). Ejemplos: AWS Lambda, Azure Functions, Google Cloud Functions.
| Característica | Servidor tradicional / VM | Contenedor (K8s) | Serverless (FaaS) |
|---|---|---|---|
| Gestionas el SO | Sí | Parcial | No |
| Escalado | Manual o configurado | Configurado | Automático (incluso a cero) |
| Coste sin tráfico | Pagas igual | Pagas igual | Cero (o casi) |
| Unidad de despliegue | Servidor/app | Contenedor | Función |
| Estado | Puede tener | Puede tener | Sin estado (stateless) |
| Control | Alto | Medio | Bajo |
- Arquitectura dirigida por eventos
El serverless brilla en arquitecturas dirigidas por eventos (event-driven): las funciones no están "siempre encendidas" esperando, sino que se activan ante un disparador (trigger). Esto encaja de forma natural con flujos asíncronos y desacoplados.
graph LR
A[Usuario sube imagen] --> B[Almacenamiento S3]
B -- evento ObjectCreated --> C[Funcion: generar miniatura]
C --> D[Guarda miniatura en S3]
C --> E[Cola de mensajes]
E --> F[Funcion: notificar usuario]Explicación del diagrama: el usuario sube una imagen al almacenamiento. Ese acto emite un evento que dispara una función para generar una miniatura. La función guarda el resultado y publica un mensaje en una cola, que a su vez dispara otra función que notifica al usuario. Cada pieza es pequeña, independiente y escala por separado. No hay servidores esperando: el código solo se ejecuta cuando ocurre algo.
- El problema del cold start (arranque en frío)
Cuando una función no se ha usado recientemente, el proveedor no tiene un entorno listo para ella. Ante la primera invocación debe: aprovisionar un contenedor, cargar el runtime (Node, Python, Java…) e inicializar tu código. Ese retraso inicial es el cold start (arranque en frío) y puede ir de decenas de milisegundos a varios segundos. Las invocaciones siguientes, mientras el entorno sigue "caliente", son rápidas (warm start).
| Factor | Efecto en el cold start |
|---|---|
| Lenguaje | Java/.NET suelen tardar más; Node/Python/Go arrancan rápido |
| Tamaño del paquete | Cuanto más grande, más tarda en cargar |
| Memoria asignada | Más memoria suele dar más CPU y arranque más veloz |
| Dependencias e inicialización | Conexiones y librerías pesadas en el arranque lo penalizan |
Mitigaciones habituales: mantener funciones pequeñas, elegir runtimes ligeros, usar concurrencia aprovisionada (entornos pre-calentados que se pagan aparte) y reutilizar conexiones fuera del handler para que persistan entre invocaciones calientes.
- Ventajas y limitaciones
| Ventajas | Limitaciones |
|---|---|
| Escalado automático, incluso a cero | Cold start: latencia en la primera invocación |
| Pago por uso real (sin coste en reposo) | Límite de tiempo de ejecución (p. ej. minutos, no horas) |
| Cero gestión de servidores y parches | Sin estado: necesitas almacenamiento externo |
| Despliegues rápidos y granulares | Dependencia del proveedor (vendor lock-in) |
| Alta disponibilidad gestionada | Depuración y monitorización más complejas |
| Ideal para cargas irregulares o en picos | Costoso si el tráfico es alto y constante |
- Ejemplo de función serverless
Una función AWS Lambda en Node.js que responde a una petición HTTP. El handler es el punto de entrada que el proveedor invoca con el event (datos del disparador) y el context (metadatos de la ejecución):
// index.js
// Conexion reutilizable: se declara FUERA del handler para
// aprovechar los "warm starts" y no reconectar en cada invocacion.
const db = require("./db").connect();
exports.handler = async (event, context) => {
try {
// 'event' contiene los datos del disparador (p. ej. la peticion HTTP)
const userId = event.queryStringParameters?.id;
if (!userId) {
return { statusCode: 400, body: JSON.stringify({ error: "Falta id" }) };
}
const user = await db.getUser(userId);
// Respuesta en el formato que espera el API Gateway
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user),
};
} catch (err) {
console.error("Error en la funcion:", err);
return { statusCode: 500, body: JSON.stringify({ error: "Error interno" }) };
}
};Explicación del código:
- La línea
const db = require("./db").connect();está fuera del handler a propósito: el código de inicialización se ejecuta una sola vez por entorno y se reutiliza en invocaciones calientes, evitando reconectar cada vez. Es una optimización clave en serverless. exports.handler = async (event, context) => {...}: el handler es la función que el proveedor llama.eventlleva los datos del disparador;contextlleva metadatos (tiempo restante, identificadores).- Se valida la entrada y, si falta el
id, se responde con código HTTP400(petición incorrecta). - Se consulta el dato y se devuelve un objeto con
statusCode,headersybody. El proveedor (vía API Gateway) traduce ese objeto en una respuesta HTTP real. - El bloque
catchregistra el error y devuelve500para no exponer detalles internos.
Para definir el disparador HTTP de forma declarativa con el Serverless Framework:
service: usuarios-api
provider:
name: aws
runtime: nodejs20.x
memorySize: 256 # MB de memoria (afecta a CPU y cold start)
timeout: 10 # segundos maximos de ejecucion
functions:
getUser:
handler: index.handler # fichero.funcion
events:
- http:
path: /usuarios
method: get # GET /usuarios dispara la funcionExplicación: runtime fija el entorno de ejecución; memorySize y timeout configuran recursos y límite de tiempo; handler apunta a index.js y a la función handler; el bloque events declara que una petición GET /usuarios invoca la función. El framework se encarga de crear la Lambda, el API Gateway y los permisos.
- Cuándo usar serverless y cuándo no
Buenos casos de uso:
- APIs y backends con tráfico irregular o impredecible (picos puntuales).
- Procesamiento de eventos: redimensionar imágenes, procesar ficheros subidos, reaccionar a mensajes de una cola.
- Tareas programadas (cron) y automatizaciones puntuales.
- Webhooks e integraciones ligeras entre sistemas.
- Prototipos y MVP donde quieres ir rápido sin montar infraestructura.
Malos casos de uso:
- Aplicaciones con tráfico alto, constante y predecible: a ese volumen suele salir más barato un servidor o contenedor reservado.
- Procesos largos (por encima del límite de tiempo de la función) o con uso intensivo de CPU/memoria sostenido.
- Cargas con latencia crítica y estricta donde el cold start sería inaceptable.
- Aplicaciones con estado en memoria persistente (las funciones son efímeras y sin estado).
Errores Comunes y Consejos
- Meter conexiones a base de datos dentro del handler. Decláralas fuera para reutilizarlas en warm starts y vigila el agotamiento del pool de conexiones, un problema clásico cuando muchas funciones escalan a la vez.
- Funciones demasiado grandes (funciones monolíticas). Mantén cada función centrada en una tarea; los paquetes grandes empeoran el cold start.
- Ignorar el coste a escala. Serverless es barato con poco tráfico, pero con millones de invocaciones constantes puede ser más caro que un contenedor. Mide.
- No diseñar para la idempotencia. Los eventos pueden entregarse más de una vez; tus funciones deben tolerar ejecuciones repetidas sin efectos duplicados.
- Olvidar la observabilidad. Al ser distribuido y efímero, sin trazas y métricas adecuadas depurar es muy difícil. Instrumenta desde el principio.
- Consejo: abraza el desacoplamiento por eventos, pero documenta bien el flujo: una maraña de funciones sin diagrama se vuelve inmanejable.
Ejercicios
- Explica por qué declarar la conexión a la base de datos fuera del handler mejora el rendimiento, y en qué tipo de invocaciones se nota.
- Una empresa tiene una API interna con tráfico constante y elevado las 24 horas. ¿Recomendarías serverless? Justifica.
- Describe un flujo event-driven serverless para procesar facturas que se suben a un almacenamiento: ¿qué disparadores y funciones encadenarías?
Soluciones
- Porque el código situado fuera del handler se ejecuta una sola vez al inicializar el entorno y se reutiliza mientras el entorno sigue caliente, evitando reabrir la conexión en cada llamada. La mejora se nota en las invocaciones calientes (warm starts) consecutivas; en el primer cold start igualmente hay que inicializar.
- No, probablemente no. Con tráfico constante y elevado las 24 h, el modelo de pago por invocación tiende a resultar más caro que un contenedor o servidor reservado, que además evita por completo el cold start. Serverless rinde mejor con tráfico irregular o con picos.
- Posible flujo: (1) el usuario sube la factura al almacenamiento de objetos, lo que emite un evento
ObjectCreated; (2) ese evento dispara una función de validación/extracción que lee el PDF y obtiene los datos; (3) la función publica un mensaje en una cola; (4) ese mensaje dispara otra función de registro que guarda los datos en una base de datos y, opcionalmente, dispara una tercera función de notificación. Cada paso es independiente, asíncrono y escala por separado.
Conclusión
Has comprendido el modelo serverless y su corazón FaaS, la arquitectura dirigida por eventos, el reto del cold start, el balance de ventajas y limitaciones, cómo se escribe una función y, sobre todo, cuándo conviene y cuándo no. Serverless es una herramienta potente para cargas irregulares y flujos por eventos, no una solución universal. En la siguiente lección recogeremos buenas prácticas transversales para construir aplicaciones robustas en la nube con los patrones de diseño cloud-native.
Curso de Arquitectura de Aplicaciones
Módulo 1: Fundamentos de la Arquitectura de Aplicaciones
- ¿Qué es la Arquitectura de Aplicaciones?
- El Rol del Arquitecto de Software
- Atributos de Calidad y Requisitos No Funcionales
- Decisiones Arquitectónicas y Compromisos (Trade-offs)
- Documentación de Arquitectura: Vistas y el Modelo C4
Módulo 2: Principios y Tácticas de Diseño
- Acoplamiento, Cohesión y Separación de Responsabilidades
- Principios SOLID Aplicados a la Arquitectura
- DRY, KISS, YAGNI y Otros Principios de Diseño
- Tácticas Arquitectónicas para los Atributos de Calidad
- Gestión de la Deuda Técnica
Módulo 3: Estilos y Patrones Arquitectónicos
- Arquitectura Monolítica
- Arquitectura en Capas (N-Tier)
- Arquitectura Cliente-Servidor
- Arquitectura Hexagonal (Puertos y Adaptadores)
- Arquitectura Limpia y Cebolla (Clean & Onion)
Módulo 4: Arquitecturas Distribuidas y Microservicios
- Introducción a los Sistemas Distribuidos
- Arquitectura de Microservicios
- Descomposición de Servicios y Bounded Contexts
- API Gateway, Service Discovery y Comunicación entre Servicios
- Patrones de Resiliencia: Circuit Breaker, Retry y Bulkhead
- El Teorema CAP y la Consistencia de Datos
Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería
- Fundamentos de la Arquitectura Orientada a Eventos
- Mensajería Asíncrona: Colas y Brokers
- Patrones de Eventos: Event Sourcing y CQRS
- Gestión de Transacciones Distribuidas: Patrón Saga
- Streaming de Datos en Tiempo Real
Módulo 6: Diseño Dirigido por el Dominio (DDD)
- Conceptos Fundamentales del DDD
- Diseño Estratégico: Bounded Contexts y Lenguaje Ubicuo
- Diseño Táctico: Entidades, Agregados y Repositorios
- Mapeo de Contextos (Context Mapping)
Módulo 7: Datos y Persistencia
- Estrategias de Persistencia: SQL vs NoSQL
- Patrones de Acceso a Datos: Repository, Unit of Work y DAO
- Base de Datos por Servicio y Gestión de Datos Distribuidos
- Caché y Estrategias de Invalidación
Módulo 8: Arquitectura en la Nube y Despliegue
- Fundamentos del Cloud Computing (IaaS, PaaS, SaaS)
- Contenedores y Orquestación con Docker y Kubernetes
- Arquitectura Serverless
- Patrones de Diseño Cloud-Native
- Infraestructura como Código (IaC)
Módulo 9: Calidad, Seguridad y Observabilidad
- Escalabilidad: Horizontal vs Vertical y Balanceo de Carga
- Alta Disponibilidad y Tolerancia a Fallos
- Seguridad por Diseño y Autenticación/Autorización
- Observabilidad: Logging, Métricas y Trazabilidad
- Rendimiento y Pruebas de Carga
