· nervico-team · arquitectura-cloud  · 12 min read

Serverless en AWS: Lambda, API Gateway y DynamoDB en la práctica

Guía práctica de arquitectura serverless en AWS: cómo diseñar APIs con Lambda y API Gateway, patrones de acceso a datos con DynamoDB, costes reales y cuándo serverless no es la respuesta.

Guía práctica de arquitectura serverless en AWS: cómo diseñar APIs con Lambda y API Gateway, patrones de acceso a datos con DynamoDB, costes reales y cuándo serverless no es la respuesta.

Serverless no significa que no haya servidores. Significa que no son tu problema. AWS gestiona el aprovisionamiento, el escalado, los parches de seguridad y la disponibilidad. Tu equipo escribe funciones, las despliega y paga solo por las invocaciones reales. Suena ideal. Y en muchos casos lo es.

Pero serverless no es una solución universal. Tiene limitaciones concretas que, si no se entienden antes de empezar, generan frustraciones, costes inesperados y arquitecturas que terminan siendo más complejas que las que intentaban reemplazar.

Este artículo explica cómo funciona la tríada Lambda + API Gateway + DynamoDB en la práctica, con patrones reales, costes verificados y las decisiones de diseño que separan una arquitectura serverless bien pensada de una que se convierte en un problema de mantenimiento.

Qué es serverless y qué no es

El modelo de ejecución

En una arquitectura serverless, el proveedor cloud ejecuta tu código en respuesta a eventos. No hay servidores que gestionar, no hay capacidad que reservar. El modelo se basa en tres principios:

  1. Ejecución bajo demanda: El código se ejecuta solo cuando llega un evento (petición HTTP, mensaje en cola, cambio en base de datos).
  2. Escalado automático: Si llegan 10 peticiones simultáneas, se crean 10 instancias de tu función. Si llegan 10.000, se crean 10.000. Sin configuración adicional.
  3. Facturación por uso: Pagas por el número de invocaciones y el tiempo de ejecución. Si no hay tráfico, no pagas nada.

Lo que serverless no resuelve

Serverless elimina la gestión de infraestructura, pero no elimina la complejidad:

  • No elimina la necesidad de arquitectura: Una aplicación serverless mal diseñada es tan problemática como un monolito mal diseñado. Los patrones de diseño siguen siendo necesarios.
  • No simplifica el debugging: Depurar una cadena de 15 funciones Lambda que se comunican a través de eventos es significativamente más difícil que depurar un monolito con un debugger local.
  • No reduce la latencia automáticamente: El cold start de Lambda añade entre 100ms y varios segundos de latencia en la primera invocación, dependiendo del runtime y el tamaño del paquete.
  • No es siempre más barato: Para cargas de trabajo constantes y predecibles, una instancia EC2 reservada puede ser 5-10 veces más económica que Lambda.

AWS Lambda: la unidad de compute

Cómo funciona internamente

Lambda ejecuta tu código dentro de un entorno de ejecución aislado llamado microVM, basado en la tecnología Firecracker que AWS desarrolló internamente. Cada invocación sigue este flujo:

  1. Evento entrante: Un trigger (API Gateway, SQS, S3, EventBridge) envía un evento al servicio Lambda.
  2. Asignación de entorno: Lambda busca un entorno de ejecución disponible. Si existe uno “caliente” (warm), reutiliza. Si no, crea uno nuevo (cold start).
  3. Ejecución: Tu función recibe el evento, lo procesa y devuelve una respuesta.
  4. Facturación: Lambda cobra por el número de invocaciones (0,20 dolares por millón) y por la duración en incrementos de 1ms (el precio depende de la memoria asignada).

Configuración que importa

Memoria: Lambda permite asignar entre 128 MB y 10.240 MB. Pero la memoria no solo afecta a la RAM disponible. AWS asigna CPU proporcionalmente a la memoria. Una función con 1.769 MB tiene 1 vCPU completa. Con 128 MB, tiene una fracción mínima de CPU. Si tu función hace procesamiento intensivo, aumentar la memoria puede hacer que se ejecute más rápido y cueste menos, porque la duración se reduce.

Timeout: El máximo es 15 minutos. Para APIs REST, un timeout de 30 segundos es razonable. Para procesamiento batch, 15 minutos puede quedarse corto. Si necesitas más, considera Step Functions o ECS.

Capas (Layers): Las dependencias compartidas entre funciones se empaquetan como capas. Una capa con el SDK de AWS, por ejemplo, evita duplicar 50 MB en cada función. El límite es 5 capas por función y 250 MB descomprimido en total.

Variables de entorno: Cadenas de conexión, API keys, configuración. Las variables sensibles deben cifrarse con AWS KMS. Nunca hardcodees secretos en el código.

Cold start: el problema real

El cold start es el tiempo que Lambda necesita para crear un nuevo entorno de ejecución. Los tiempos varían según el runtime:

RuntimeCold start típicoCon VPC
Python100-300ms200-500ms
Node.js100-300ms200-500ms
Java800ms-3s1-5s
.NET400ms-1.5s600ms-2.5s
Rust/Go10-50ms50-200ms

Soluciones prácticas:

  • Provisioned Concurrency: Mantiene N instancias siempre calientes. Elimina el cold start, pero introduces un coste fijo. Útil para funciones críticas con SLA de latencia.
  • SnapStart (solo Java): AWS congela el estado de la JVM tras la inicialización y lo restaura en cada invocación. Reduce el cold start de Java a menos de 200ms.
  • Minimizar el paquete: Cada MB adicional incrementa el cold start. Usa tree-shaking, elimina dependencias innecesarias, considera runtimes ligeros como Rust para funciones críticas en latencia.

API Gateway: la puerta de entrada

REST API vs HTTP API

AWS ofrece dos tipos de API Gateway, y la decisión importa más de lo que parece:

HTTP API (recomendada para la mayoría de casos):

  • Coste: 1,00 dolar por millón de peticiones.
  • Latencia: 60% menor que REST API.
  • Soporta JWT authorizers nativos, CORS automático, integración con Lambda, rutas con parámetros.
  • No soporta: planes de uso (usage plans), API keys como mecanismo de autenticación, transformaciones de request/response, validación de esquema integrada.

REST API (para casos específicos):

  • Coste: 3,50 dolares por millón de peticiones.
  • Soporta todo lo anterior más: WAF, caché integrado, planes de uso con throttling por API key, modelos de validación, transformaciones con VTL.
  • Necesaria si requieres: caché de respuestas a nivel de API, IP whitelisting con WAF, monetización por API key.

Recomendación práctica: Empieza con HTTP API. Si necesitas caché o WAF, migra a REST API. La estructura de rutas es compatible.

Patrones de integración

La forma más directa es la integración proxy con Lambda:

GET /users/{id} → Lambda function → respuesta JSON
POST /users     → Lambda function → respuesta JSON

Cada ruta puede apuntar a una función Lambda diferente (un handler por endpoint) o a una única función que enruta internamente (monolambda). La decisión tiene consecuencias:

Un handler por endpoint:

  • Despliegues independientes por endpoint.
  • Paquetes más pequeños, cold starts más rápidos.
  • Mayor granularidad en permisos IAM.
  • Más funciones que gestionar.

Monolambda (una función para toda la API):

  • Un solo despliegue, un solo paquete.
  • Paquete más grande, cold starts más lentos.
  • Más simple de desarrollar localmente.
  • Menos granularidad en permisos.

Para APIs con menos de 20 endpoints, monolambda suele ser la opción más práctica. Para APIs grandes o con equipos múltiples, un handler por endpoint permite despliegues independientes.

Autenticación y autorización

API Gateway soporta tres mecanismos de autenticación:

  1. JWT Authorizer (HTTP API): Valida tokens JWT de cualquier proveedor OIDC (Cognito, Auth0, Firebase Auth). Sin coste adicional, sin Lambda adicional. Es la opción más simple y eficiente.
  2. Lambda Authorizer: Una función Lambda que recibe el token, lo valida y devuelve una política IAM. Útil cuando necesitas lógica de autorización compleja (roles, permisos granulares, consultas a base de datos).
  3. IAM Authorization: Usa firmas SigV4. Ideal para comunicación entre servicios AWS, no para APIs públicas.

DynamoDB: diseño de datos para serverless

El cambio de mentalidad

DynamoDB no es una base de datos relacional. No soporta JOINs. No tiene un lenguaje de consulta flexible como SQL. Y eso es intencional. DynamoDB está diseñada para ofrecer latencia de milisegundos a cualquier escala, pero exige que pienses en los patrones de acceso antes de diseñar la tabla.

En una base de datos relacional, diseñas las tablas primero y las consultas después. En DynamoDB, es al revés: primero defines todas las consultas que tu aplicación necesita, y después diseñas la tabla para soportarlas.

Modelo de tabla única (Single Table Design)

El patrón más potente de DynamoDB es el diseño de tabla única. En lugar de crear una tabla por entidad (Users, Orders, Products), almacenas todas las entidades en una sola tabla con claves genéricas:

PK (Partition Key)     | SK (Sort Key)          | Datos
-----------------------|------------------------|------------------
USER#123               | PROFILE                | {name, email...}
USER#123               | ORDER#2024-001         | {total, status...}
USER#123               | ORDER#2024-002         | {total, status...}
PRODUCT#abc            | METADATA               | {name, price...}
PRODUCT#abc            | REVIEW#2024-001        | {rating, text...}

Ventajas:

  • Una sola operación Query con PK = USER#123 devuelve el perfil del usuario y todos sus pedidos.
  • Sin JOINs, sin consultas adicionales, sin latencia añadida.
  • El escalado es automático: DynamoDB distribuye los datos por partition key.

Desventajas:

  • El diseño inicial requiere conocer todos los patrones de acceso.
  • Los cambios posteriores en patrones de acceso pueden exigir migración de datos.
  • La curva de aprendizaje es pronunciada para equipos acostumbrados a SQL.

Modos de capacidad y coste

DynamoDB ofrece dos modos de facturación:

On-Demand (pago por uso):

  • 1,25 dolares por millón de escrituras.
  • 0,25 dolares por millón de lecturas.
  • Sin capacidad que planificar.
  • Ideal para cargas impredecibles o en fase de descubrimiento.

Provisioned (capacidad reservada):

  • Defines unidades de lectura/escritura por segundo.
  • Más económico para cargas predecibles (hasta 70% de ahorro con Reserved Capacity).
  • Riesgo de throttling si subestimas la capacidad.

Estrategia recomendada: Empieza en modo On-Demand. Cuando tu patrón de tráfico sea estable y predecible (normalmente tras 3-6 meses en producción), evalúa si Provisioned con auto-scaling reduce costes.

Índices secundarios globales (GSI)

Los GSI permiten consultar la tabla con claves alternativas. Si tu tabla principal tiene PK = USER#123, pero necesitas buscar por email, creas un GSI con PK = email:

Cada GSI es una copia parcial de la tabla con un esquema de claves diferente. Consume capacidad de lectura/escritura adicional. El límite es 20 GSIs por tabla.

Regla práctica: Si necesitas más de 5 GSIs, probablemente tu diseño de tabla necesita revisión. Un buen diseño de tabla única cubre la mayoría de patrones de acceso con 2-3 GSIs.

Patrones de arquitectura serverless

API REST síncrona

El patrón más común:

Cliente → API Gateway → Lambda → DynamoDB → Respuesta

Apropiado para: CRUD, consultas, operaciones que deben responder en menos de 3 segundos.

Procesamiento asíncrono con colas

Para operaciones que no necesitan respuesta inmediata:

Cliente → API Gateway → Lambda (validación) → SQS → Lambda (procesamiento) → DynamoDB

Ventajas: Desacopla la recepción del procesamiento. Si el procesamiento falla, el mensaje vuelve a la cola. Si hay un pico de carga, SQS absorbe los mensajes y Lambda los procesa al ritmo que pueda.

Event-driven con EventBridge

Para comunicación entre dominios:

Servicio A → EventBridge → Regla 1 → Lambda (notificaciones)
                         → Regla 2 → Lambda (analytics)
                         → Regla 3 → Step Functions (workflow)

EventBridge permite que los servicios emitan eventos sin conocer a los consumidores. Es el patrón fundamental para arquitecturas serverless con múltiples dominios.

Orquestación con Step Functions

Para workflows que involucran múltiples pasos con lógica condicional, reintentos y gestión de errores:

Step Functions:
  1. Validar datos (Lambda)
  2. Si válido → Procesar pago (Lambda)
  3. Si pago OK → Generar factura (Lambda) + Enviar email (SES)
  4. Si pago KO → Notificar error (SNS) + Reintentar (hasta 3 veces)

Step Functions es preferible a encadenar Lambdas directamente porque gestiona reintentos, errores y timeouts de forma declarativa. El coste es 0,025 dolares por cada 1.000 transiciones de estado.

Costes reales: serverless en números

Escenario 1: API REST con 100.000 usuarios activos/mes

Estimación para una API con 50 endpoints, 10 millones de peticiones/mes y 500 GB de almacenamiento en DynamoDB:

ServicioConfiguraciónCoste/mes
Lambda10M invocaciones, 200ms avg, 256MB~20 dolares
API Gateway (HTTP)10M peticiones~10 dolares
DynamoDB (On-Demand)5M escrituras + 30M lecturas~14 dolares
DynamoDB Storage500 GB~125 dolares
CloudWatch Logs10 GB/mes~5 dolares
Total~174 dolares

Escenario 2: la misma carga en EC2

ServicioConfiguraciónCoste/mes
EC2 (2x t3.medium)On-Demand, 24/7~122 dolares
ALBApplication Load Balancer~25 dolares
RDS (db.t3.medium)PostgreSQL, Multi-AZ~150 dolares
CloudWatchMétricas + logs~10 dolares
Total~307 dolares

En este escenario, serverless es un 43% más barato. Pero si la carga sube a 100 millones de peticiones/mes con tráfico constante 24/7, EC2 con Reserved Instances puede ser más económico.

El punto de inflexión

No existe una regla universal, pero como referencia:

  • Menos de 50M peticiones/mes con tráfico variable: Serverless suele ganar.
  • Más de 100M peticiones/mes con tráfico constante: EC2/ECS con Reserved Instances suele ser más económico.
  • Tráfico con picos extremos (eventos, lanzamientos): Serverless gana por escalado automático, independientemente del volumen.

Cuándo no usar serverless

Serverless no es la respuesta correcta para todos los casos. Estas situaciones requieren considerar alternativas:

Aplicaciones con estado persistente en memoria

Websockets de larga duración, caché en memoria, conexiones de base de datos persistentes. Lambda crea y destruye instancias constantemente. Si tu aplicación depende de mantener estado entre peticiones, necesitas contenedores (ECS/EKS) o instancias EC2.

Procesamiento de larga duración

Lambda tiene un límite de 15 minutos. Si necesitas procesar archivos de vídeo, entrenar modelos o ejecutar ETLs que duran horas, Lambda no es viable. Usa ECS Fargate para tareas batch o AWS Batch para procesamiento a escala.

Latencia ultra-baja garantizada

Si tu SLA exige respuestas en menos de 10ms de forma consistente, el cold start de Lambda es un riesgo. Provisioned Concurrency mitiga el problema, pero añade coste fijo y no garantiza latencia sub-10ms.

Cargas de trabajo predecibles y constantes

Un servicio que procesa la misma carga 24/7 no se beneficia del modelo de pago por uso. EC2 con Reserved Instances o Savings Plans será significativamente más económico.

Herramientas para desarrollo local

Desarrollar y testear funciones Lambda en local requiere herramientas específicas:

  • AWS SAM (Serverless Application Model): Framework de AWS para definir, testear y desplegar aplicaciones serverless. Incluye sam local invoke para ejecutar funciones localmente y sam local start-api para emular API Gateway.
  • Serverless Framework: Alternativa de terceros con mayor ecosistema de plugins. Soporta múltiples proveedores cloud.
  • LocalStack: Emula servicios AWS en Docker. Útil para pruebas de integración sin coste.
  • SST (Serverless Stack): Framework moderno con live lambda development, que conecta tu código local directamente con los servicios AWS reales.

Infraestructura como código para serverless

No despliegues serverless desde la consola. Nunca. Usa infraestructura como código desde el primer día:

  • AWS CDK: Define infraestructura en TypeScript, Python o Java. Genera CloudFormation. Es la opción más potente si tu equipo ya programa en estos lenguajes.
  • Terraform: Agnóstico de proveedor. Más verboso que CDK pero con un ecosistema enorme y sin dependencia de CloudFormation.
  • AWS SAM: Extensión de CloudFormation simplificada para serverless. Menos flexible que CDK pero más conciso para casos puramente serverless.

Conclusión

Serverless en AWS es una herramienta poderosa cuando se aplica al problema correcto. Lambda + API Gateway + DynamoDB forman una tríada que permite construir APIs escalables con costes predecibles y operación mínima. Pero no es magia. Requiere diseñar los patrones de acceso a datos antes de escribir código, entender los límites del cold start, y aceptar que el debugging distribuido es inherentemente más complejo.

La decisión entre serverless y contenedores no es binaria. Muchas arquitecturas exitosas combinan ambos: serverless para APIs y procesamiento de eventos, contenedores para servicios con estado y procesamiento de larga duración.

Si estás evaluando una migración a serverless o diseñando una nueva arquitectura en AWS, en NERVICO ayudamos a equipos técnicos a tomar estas decisiones con datos, no con hype. Solicita una auditoría gratuita y revisamos tu arquitectura actual para identificar dónde serverless tiene sentido y dónde no.

Back to Blog

Related Posts

View All Posts »