DEV Community

David Rodriguez
David Rodriguez

Posted on • Originally published at devopsfreelance.pro

Serverless vs Microservicios: Diferencias Clave y Cuándo Elegir Cada Arquitectura

Serverless y microservicios son dos enfoques arquitectónicos que pueden convivir o usarse por separado. Serverless ejecuta funciones individuales sin gestionar servidores. Microservicios descomponen una aplicación en servicios independientes que se despliegan por separado. La decisión entre uno y otro depende del tipo de carga de trabajo, el equipo y los costos.

Serverless y Microservicios: No Son lo Mismo

Un error frecuente es tratar serverless y microservicios como si fueran alternativas directas. En realidad, operan en niveles diferentes:

  • Microservicios es un patrón de arquitectura: cómo divides tu aplicación en componentes independientes
  • Serverless es un modelo de ejecución: cómo y dónde se ejecuta tu código

Puedes tener microservicios que corren en servidores tradicionales, en contenedores, o en funciones serverless. Y puedes usar serverless para ejecutar un monolito o funciones independientes que no siguen el patrón de microservicios.

Dicho esto, en la práctica la decisión suele ser entre estas dos opciones concretas:

  1. Microservicios en contenedores (Docker + Kubernetes/ECS)
  2. Funciones serverless (AWS Lambda, Azure Functions, Google Cloud Functions)

Esta guía compara ambos enfoques en profundidad.

Arquitectura de Microservicios

Los microservicios descomponen una aplicación en servicios pequeños e independientes, cada uno responsable de una función de negocio específica.

Características Principales

  • Independencia de despliegue: Cada servicio se despliega por separado
  • Base de datos propia: Cada servicio gestiona sus propios datos
  • Comunicación por API: Los servicios se comunican via HTTP/REST, gRPC o eventos
  • Autonomía de equipo: Un equipo pequeño es dueño de un servicio completo
  • Tecnología heterogénea: Cada servicio puede usar el lenguaje y stack que mejor le sirva

Ejemplo: E-commerce con Microservicios

                    ┌─────────────┐
                    │ API Gateway │
                    └──────┬──────┘
           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
    ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
    │   User       │ │   Product    │ │   Order      │
    │   Service    │ │   Service    │ │   Service    │
    │   (Node.js)  │ │   (Python)   │ │   (Java)     │
    └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
           ▼               ▼               ▼
    ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
    │  PostgreSQL  │ │  MongoDB     │ │  PostgreSQL  │
    └──────────────┘ └──────────────┘ └──────────────┘
           │               │               │
           └───────────────┼───────────────┘
                           ▼
                    ┌──────────────┐
                    │  Event Bus   │
                    │  (Kafka/SQS) │
                    └──────────────┘
Enter fullscreen mode Exit fullscreen mode

Microservicio Típico en Producción

# Kubernetes deployment para un microservicio
apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: product-service
  template:
    spec:
      containers:
      - name: product-service
        image: registry/product-service:2.1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "1000m"
            memory: "512Mi"
        env:
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: product-db
              key: host
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
Enter fullscreen mode Exit fullscreen mode

Arquitectura Serverless

En serverless, el código se ejecuta en funciones efímeras que el proveedor cloud provisiona automáticamente. No hay servidores que gestionar, no hay instancias que escalar manualmente.

Características Principales

  • Sin gestión de servidores: El proveedor maneja toda la infraestructura
  • Pago por ejecución: Solo pagas cuando tu código se ejecuta
  • Escalado automático a cero: Sin tráfico, sin costo
  • Funciones de corta duración: Timeouts de 15 minutos (Lambda) a 60 minutos (Azure)
  • Event-driven: Se activan por eventos (HTTP, colas, archivos, schedules)

Ejemplo: E-commerce con Serverless

                    ┌──────────────┐
                    │ API Gateway  │
                    └──────┬───────┘
           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
    ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
    │  Lambda:     │ │  Lambda:     │ │  Lambda:     │
    │  getUser     │ │  getProducts │ │  createOrder │
    │  createUser  │ │  search      │ │  getOrder    │
    │  updateUser  │ │  updateStock │ │  cancelOrder │
    └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
           ▼               ▼               ▼
    ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
    │  DynamoDB    │ │  DynamoDB    │ │  DynamoDB    │
    └──────────────┘ └──────────────┘ └──────────────┘
           │               │               │
           └───────────────┼───────────────┘
                           ▼
                    ┌──────────────┐
                    │   EventBridge│
                    │   / SQS     │
                    └──────────────┘
Enter fullscreen mode Exit fullscreen mode

Función Serverless Típica

# AWS Lambda: crear orden de compra
import json
import boto3
import uuid
from datetime import datetime

dynamodb = boto3.resource('dynamodb')
orders_table = dynamodb.Table('orders')
sqs = boto3.client('sqs')

def handler(event, context):
    body = json.loads(event['body'])

    order = {
        'order_id': str(uuid.uuid4()),
        'user_id': body['user_id'],
        'items': body['items'],
        'total': calculate_total(body['items']),
        'status': 'pending',
        'created_at': datetime.utcnow().isoformat()
    }

    # Guardar orden
    orders_table.put_item(Item=order)

    # Publicar evento para procesamiento async
    sqs.send_message(
        QueueUrl='https://sqs.us-east-1.amazonaws.com/123/order-processing',
        MessageBody=json.dumps({
            'event': 'order.created',
            'order_id': order['order_id'],
            'items': order['items']
        })
    )

    return {
        'statusCode': 201,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps({
            'order_id': order['order_id'],
            'status': 'pending'
        })
    }

def calculate_total(items):
    return sum(item['price'] * item['quantity'] for item in items)
Enter fullscreen mode Exit fullscreen mode

Comparación Detallada

Costos

Factor Microservicios (Contenedores) Serverless
Costo base Si (instancias siempre encendidas) No (pago por ejecución)
Con 0 tráfico ~$50-200/mes por servicio ~$0
Con tráfico constante Predecible, optimizable Puede ser más caro
Picos de tráfico Costo proporcional a capacidad reservada Costo proporcional al uso real
Ejemplo: 1M requests/mes ~$100-300/mes (ECS Fargate) ~$20-50/mes (Lambda)
Ejemplo: 100M requests/mes ~$500-1,500/mes ~$2,000-5,000/mes

Regla general: Serverless es más barato con tráfico bajo o variable. Microservicios en contenedores son más baratos con tráfico alto y constante.

Escalabilidad

Aspecto Microservicios Serverless
Velocidad de escalado 30s-5min (nuevo contenedor) Instantáneo (ms)
Escala a cero No (mínimo 1 instancia) Si
Escalado máximo Limitado por nodos/presupuesto 1000+ ejecuciones concurrentes
Granularidad Por servicio Por función individual
Cold start No aplica 100ms-10s según runtime

Desarrollo y Mantenimiento

Aspecto Microservicios Serverless
Complejidad de desarrollo Media (frameworks estándar) Baja-Media (funciones simples)
Testing local Excelente (Docker Compose) Limitado (emuladores imprecisos)
Debugging Fácil (logs locales, debugger) Complejo (CloudWatch, tracing)
Vendor lock-in Bajo (contenedores portables) Alto (APIs propietarias)
Time-to-market Medio Rápido
Operación día a día Clusters, patching, updates Casi nula
Equipo necesario DevOps/SRE dedicado Developers pueden operar

Arquitectura y Diseño

Aspecto Microservicios Serverless
Estado (state) Stateful o stateless Solo stateless
Conexiones a DB Connection pools persistentes Conexiones efímeras (problema!)
Procesos largos Sin límite 15 min máximo (Lambda)
WebSockets Si Limitado (API Gateway WS)
Background jobs Si (workers, queues) Si (SQS + Lambda)
Tamaño del código Sin límite práctico 50-250MB según proveedor

Cuándo Elegir Microservicios

Los microservicios en contenedores son la mejor opción cuando:

1. Tráfico Alto y Constante

Si tu aplicación maneja tráfico predecible y constante (como un SaaS con miles de usuarios concurrentes), los contenedores siempre encendidos son más eficientes que pagar por cada ejecución serverless.

2. Procesos de Larga Duración

Procesamiento de video, entrenamiento de modelos ML, ETL pesados, WebSockets para real-time: cualquier proceso que exceda el timeout de Lambda (15 minutos) necesita contenedores.

3. Estado y Conexiones Persistentes

Aplicaciones que mantienen conexiones abiertas a bases de datos, caches en memoria, o sesiones de usuario se benefician de contenedores que no se destruyen entre requests.

4. Control y Portabilidad

Si necesitas controlar el runtime, el sistema operativo, las versiones de librerías, o poder migrar entre clouds sin reescribir, los contenedores ofrecen esa flexibilidad.

5. Equipos Grandes con Dominio Claro

Cuando tienes equipos dedicados por dominio de negocio (equipo de pagos, equipo de usuarios, equipo de productos), cada uno puede ser dueño de su microservicio.

Cuándo Elegir Serverless

Serverless es la mejor opción cuando:

1. Tráfico Variable o Impredecible

APIs que van de 0 a 10,000 requests en minutos y luego vuelven a 0. Colas que se llenan esporádicamente. Webhooks que se reciben intermitentemente.

2. Event-Driven Processing

Procesamiento de archivos subidos a S3, reacción a eventos de bases de datos, procesamiento de streams de datos, envío de notificaciones disparadas por eventos.

3. APIs Simples y CRUD

Si tu API es principalmente operaciones de lectura/escritura contra una base de datos, Lambda + API Gateway + DynamoDB es extremadamente eficiente.

4. Equipos Pequeños sin DevOps

Si no tienes un equipo dedicado a operar infraestructura, serverless elimina la necesidad de gestionar clusters, patchar servidores y configurar autoscaling.

5. Funciones Auxiliares

Procesamiento de imágenes, envío de emails, generación de reportes, tareas scheduladas, integración entre servicios: funciones que no justifican un servicio completo.

# Lambda ideal: procesar imagen subida a S3
def handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']

    # Descargar imagen
    image = s3.get_object(Bucket=bucket, Key=key)

    # Generar thumbnails
    for size in [(150, 150), (300, 300), (800, 600)]:
        thumbnail = resize_image(image, size)
        s3.put_object(
            Bucket=bucket,
            Key=f"thumbnails/{size[0]}x{size[1]}/{key}",
            Body=thumbnail
        )

    return {'processed': key, 'thumbnails': 3}
Enter fullscreen mode Exit fullscreen mode

Patrón Híbrido: Lo Mejor de Ambos Mundos

En la práctica, muchas arquitecturas exitosas combinan microservicios y serverless:

┌─────────────────────────────────────────────────────┐
│                   API Gateway                        │
└──────────────────────┬──────────────────────────────┘
                       │
    ┌──────────────────┼──────────────────┐
    │                  │                  │
    ▼                  ▼                  ▼
┌─────────┐    ┌─────────────┐    ┌──────────────┐
│ Lambda  │    │ Microservicio│    │ Lambda       │
│ Auth    │    │ Core API     │    │ Notifications│
│         │    │ (ECS/K8s)    │    │              │
└─────────┘    └──────┬──────┘    └──────────────┘
                      │
              ┌───────┼───────┐
              ▼       ▼       ▼
         ┌────────┐ ┌────┐ ┌──────────┐
         │  RDS   │ │Redis│ │  Lambda  │
         │        │ │    │ │  Image   │
         │        │ │    │ │  Process │
         └────────┘ └────┘ └──────────┘
Enter fullscreen mode Exit fullscreen mode

Qué Va en Microservicios

  • Core business logic (procesamiento de pagos, gestión de usuarios)
  • Servicios con conexiones persistentes a DB
  • APIs con tráfico alto y constante
  • Servicios que necesitan WebSockets o streaming

Qué Va en Serverless

  • Autenticación y autorización (funciones simples, stateless)
  • Procesamiento de eventos y archivos
  • Notificaciones (email, push, SMS)
  • Tareas scheduladas (reportes, limpieza, backups)
  • Endpoints de baja frecuencia

Problemas Comunes y Soluciones

Cold Starts en Serverless

El cold start ocurre cuando Lambda necesita inicializar un nuevo entorno de ejecución. Puede agregar 100ms a 10 segundos de latencia.

Soluciones:

  • Usar Provisioned Concurrency para funciones críticas
  • Elegir runtimes rápidos (Python, Node.js vs Java)
  • Minimizar el tamaño del paquete de despliegue
  • Usar SnapStart en Java (Lambda)

Distributed Tracing en Microservicios

Con muchos servicios comunicándose, un request puede pasar por 5-10 servicios. Sin tracing, debuggear es una pesadilla.

Soluciones:

  • Implementar OpenTelemetry para traces distribuidos
  • Usar correlation IDs que se propagan entre servicios
  • Centralizar logs con un stack como ELK o Graylog

Connection Pooling en Serverless

Cada invocación de Lambda puede abrir una nueva conexión a la base de datos, agotando el pool rápidamente.

Soluciones:

  • Usar RDS Proxy o PgBouncer
  • Preferir DynamoDB (sin connection pooling)
  • Reutilizar conexiones entre invocaciones calientes

Matriz de Decisión

Pregunta Microservicios Serverless
¿Tráfico constante > 10K req/min? X
¿Procesos > 15 minutos? X
¿Necesitas WebSockets? X
¿Equipo DevOps dedicado? X
¿Tráfico variable o esporádico? X
¿Event-driven processing? X
¿Equipo pequeño sin infra? X
¿Time-to-market es prioridad? X
¿Multi-cloud obligatorio? X
¿Presupuesto ajustado, bajo uso? X

Conclusión

No existe una respuesta universal. La decisión entre serverless y microservicios depende de tu contexto específico:

  • Elige microservicios en contenedores si tienes tráfico alto y constante, procesos de larga duración, o necesitas control total sobre el entorno de ejecución
  • Elige serverless si tienes tráfico variable, equipo pequeño, o muchas funciones event-driven independientes
  • Combina ambos en una arquitectura híbrida donde cada componente usa el modelo que mejor le sirve

Lo peor que puedes hacer es elegir por hype. Evalúa tu tráfico, tu equipo, tu presupuesto y tus requisitos técnicos. La arquitectura correcta es la que resuelve tus problemas con la menor complejidad posible.

Para complementar tu decisión, consulta nuestra guía de contenedores vs serverless que profundiza en los aspectos de infraestructura, y nuestra guía sobre seguridad en microservicios para consideraciones de seguridad en ambos enfoques.

Top comments (0)