Artículo

Arquitectura sin servidor

Arquitectura sin servidor

La informática sin servidor permite a los desarrolladores crear y ejecutar aplicaciones sin administrar servidores. El proveedor de la nube maneja toda la infraestructura: aprovisionamiento, escalamiento, parches y mantenimiento. Los desarrolladores escriben funciones, configuran activadores y la plataforma se encarga del resto.

3 min de lecturaIdioma: ES EspañolGratis0 aplausos0 comentarios
TecnologíaArtículos de ingenieríaArchitectureServerlessTechnologyEngineering ArticlesCloud Computing
Opciones de lectura

Introducción

La informática sin servidor permite a los desarrolladores crear y ejecutar aplicaciones sin administrar servidores. El proveedor de la nube maneja toda la infraestructura: aprovisionamiento, escalamiento, parches y mantenimiento. Los desarrolladores escriben funciones, configuran activadores y la plataforma se encarga del resto.

El nombre "sin servidor" es engañoso: los servidores todavía están involucrados. Pero el desarrollador nunca piensa en ellos. Este cambio de la gestión de infraestructura a la lógica pura de las aplicaciones está transformando la forma en que se crean e implementan las aplicaciones.


Cómo funciona la tecnología sin servidor

El modelo de ejecución

                     ┌─────────────────────┐
                     │   Event Source      │
                     │ (HTTP, Queue, Timer,│
                     │  Storage, etc.)     │
                     └──────────┬──────────┘
                                │ Trigger
                                ▼
┌──────────────────────────────────────────────────┐
│              Serverless Function                 │
│  ┌────────────────────────────────────────────┐  │
│  │   1. Cold Start (if needed)               │  │
│  │      - Provision sandbox                  │  │
│  │      - Initialize runtime (Node, Python)  │  │
│  │      - Load dependencies                  │  │
│  ├────────────────────────────────────────────┤  │
│  │   2. Execute handler function              │  │
│  │   3. Return response                       │  │
│  └────────────────────────────────────────────┘  │
│              Auto-scales horizontally             │
│              from 0 to N concurrent executions    │
└──────────────────────────────────────────────────┘

Función sencilla sin servidor

// AWS Lambda handler
exports.handler = async (event) => {
  const { name } = JSON.parse(event.body);

  const response = {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      message: `Hello, ${name}!`,
      timestamp: new Date().toISOString()
    })
  };

  return response;
};

Arquitectura sin servidor versus arquitectura tradicional

Aspecto Tradicional (servidores) Sin servidor
Gestión de servidores Requerido (parches, actualizaciones) Ninguno
Escalado Grupos de escalado manual o automático Automático, de 0 a 1000s
Facturación Por hora/instancia (costo inactivo) Por ejecución + por memoria (sin costo de inactividad)
Arranques en frío N/A (siempre activado) 100 ms-1 s para la invocación inicial
Ejecución máxima Ilimitado Tiempo de espera (15 min Lambda, 10 min Funciones de nube)
Estado Persistente (estado en memoria) Apátrida por diseño
Implementación Servidor o contenedor completo Función única
Granularidad Monolito o servicio Función única

Orígenes de eventos sin servidor

Desencadenantes comunes

Fuente del evento Proveedor Caso de uso
HTTP (Puerta de enlace API) AWS, Azure, GCP API REST, webhooks
Cambio de base de datos (CDC) Flujos de DynamoDB, fuente de cambios de CosmosDB, Firestore Sincronizar datos, activar flujos de trabajo
Carga de archivos S3, almacenamiento de blobs, almacenamiento en la nube Procesamiento de imágenes, validación de archivos.
Cola de mensajes SQS, almacenamiento en cola, Pub/Sub Procesamiento asíncrono desacoplado
Transmitir Kinesis, centros de eventos, pub/sub Procesamiento de datos en tiempo real
Horario Eventos de CloudWatch, temporizador, programador Trabajos cron, procesamiento por lotes
Correo electrónico SES, SendGrid Procesamiento de correo electrónico
IoT Núcleo de IoT, Event Grid Procesamiento de telemetría del dispositivo

Función de eventos múltiples

# AWS SAM template — Function triggered by multiple events
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  OrderProcessor:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: orders.handler
      Runtime: nodejs20.x
      Events:
        HttpPost:
          Type: Api
          Properties:
            Path: /orders
            Method: POST
        QueueConsumer:
          Type: SQS
          Properties:
            Queue: !GetAtt OrderQueue.Arn
            BatchSize: 10
        StreamProcessor:
          Type: DynamoDB
          Properties:
            Stream: !GetAtt OrdersTable.StreamArn
            StartingPosition: TRIM_HORIZON

Creación de una aplicación sin servidor

Ejemplo: canal de procesamiento de imágenes

                  ┌──────────┐
                  │ User     │
                  │ Uploads  │
                  └────┬─────┘
                       ▼
              ┌─────────────────┐
              │  S3 Bucket      │
              │  (upload/raw)   │
              └────────┬────────┘
                       │ trigger
                       ▼
              ┌─────────────────┐
              │  Lambda         │
              │  (process.ts)   │
              │                 │
              │   1. Read image │
              │   2. Resize     │
              │   3. Compress   │
              │   4. Extract    │
              │      metadata   │
              └────────┬────────┘
                       │
               ┌───────┴───────┐
               ▼               ▼
        ┌────────────┐  ┌──────────────┐
        │ S3 Bucket  │  │ DynamoDB    │
        │ (processed)│  │ (metadata)  │
        └────────────┘  └──────────────┘
// process.ts — Image processing Lambda
import { S3 } from '@aws-sdk/client-s3';
import { DynamoDB } from '@aws-sdk/client-dynamodb';
import sharp from 'sharp';

const s3 = new S3();
const dynamo = new DynamoDB();

const SUPPORTED_FORMATS = ['image/jpeg', 'image/png', 'image/webp'];

export const handler = async (event: S3Event) => {
  const results = await Promise.allSettled(
    event.Records.map(async (record) => {
      const bucket = record.s3.bucket.name;
      const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));

      // Validate file type
      const headResult = await s3.headObject({ Bucket: bucket, Key: key });
      if (!SUPPORTED_FORMATS.includes(headResult.ContentType!)) {
        console.log(`Unsupported format: ${headResult.ContentType}`);
        return;
      }

      // Read original
      const { Body } = await s3.getObject({ Bucket: bucket, Key: key });
      const buffer = await Body!.transformToByteArray();

      // Process: resize to multiple sizes
      const sizes = [
        { suffix: 'thumbnail', width: 150, height: 150 },
        { suffix: 'medium', width: 800, height: 600 },
        { suffix: 'large', width: 1920, height: 1080 },
      ];

      for (const size of sizes) {
        const processed = await sharp(buffer)
          .resize(size.width, size.height, { fit: 'cover' })
          .webp({ quality: 80 })
          .toBuffer();

        const outputKey = key.replace('raw', `processed/${size.suffix}`);
        await s3.putObject({
          Bucket: bucket.replace('-raw', '-processed'),
          Key: outputKey,
          Body: processed,
          ContentType: 'image/webp',
        });
      }

      // Store metadata
      await dynamo.putItem({
        TableName: 'ImageMetadata',
        Item: {
          imageId: { S: key },
          originalSize: { N: buffer.byteLength.toString() },
          formats: { SS: ['thumbnail', 'medium', 'large'] },
          uploadedAt: { S: new Date().toISOString() },
        },
      });
    })
  );

  const failed = results.filter(r => r.status === 'rejected');
  if (failed.length > 0) {
    throw new Error(`${failed.length} images failed processing`);
  }

  return { processed: results.length - failed.length, failed: failed.length };
};

Arranques en frío y mitigación

¿Qué causa los arranques en frío?

Cuando una función está inactiva, la plataforma recupera sus recursos. La siguiente invocación requiere:

  1. Tiempo de ejecución de aprovisionamiento (~50 ms: Node.js, Python; ~500 ms: Java, C#)
  2. Inicializar dependencias (~50-500 ms dependiendo del tamaño del paquete)
  3. Ejecutar código del controlador (~10-50ms fuera del controlador)

Arranque en frío total: 100 ms a 2 s según el tiempo de ejecución y el tamaño del paquete.

Tiempos de inicio en frío por tiempo de ejecución

Tiempo de ejecución Arranque en frío (mediana) Arranque en frío (p99)
pitón 200 ms 500ms
Nodo.js 250 ms 600 ms
ir 100 ms 300 ms
.NET 500ms 2s
Java 800ms 3s
óxido 100 ms 250 ms

Estrategias de mitigación

Estrategia Cómo funciona Impacto en los costos
Simultaneidad aprovisionada (Lambda) Mantenga N instancias siempre calientes Paga por instancias cálidas
Inicio instantáneo (Lambda) Preinicialización y tiempo de ejecución de instantáneas Costo adicional mínimo
Pings para mantener el calor Invocaciones periódicas cada 5 minutos insignificante
Tiempo de ejecución más ligero Utilice Node.js/Python/Go en lugar de Java Sin coste adicional
Minimizar dependencias Paquetes de implementación más pequeños Sin coste adicional

Costos sin servidor

Modelo de precios

La mayoría de las plataformas sin servidor cobran según:

  1. Solicitudes: número de invocaciones de funciones.
  2. Duración: tiempo de ejecución (redondeado al 1 ms o 100 ms más cercano).
  3. Memoria: memoria configurada por invocación.

Ejemplo de comparación de costos

Scenario: API handling 1M requests/month, 200ms avg execution, 512MB memory

Traditional (t3.small, $0.0208/hr):
  $0.0208 × 730 hours = $15.18/month (always on)

Serverless (Lambda):
  Requests: 1M × $0.20/1M = $0.20
  Duration: 1M × 0.2s × 512MB/1024MB × $0.0000166667/GB-s = $1.67
  Total: $1.87/month

Savings: ~87% at low traffic

Breakeven point: At ~45M requests/month, traditional becomes cheaper

Optimización de costos

# Serverless cost optimization checklist
cost_optimization:
  - "Right-size memory: 128MB may be sufficient, but 1769MB costs 14x more"
  - "Use AWS Compute Optimizer for memory recommendations"
  - "Minimize function duration (optimize code, use async where possible)"
  - "Use reserved concurrency only when needed"
  - "Delete unused functions and resources"
  - "Use Lambda SnapStart for Java/.NET to reduce duration"
  - "Leverage Lambda@Edge or CloudFront Functions for edge processing"

Ecosistema sin servidor

calcular

Servicio Proveedor Característica clave
AWS Lambda AWS Ecosistema más grande, tiempo de espera de 15 minutos
Funciones de Azure microsoft Integración profunda de Office 365/Teams
Funciones en la nube google Integración eventarc primero en Python
Trabajadores de Cloudflare Llamarada de nube Basado en el borde, arranques en frío <1 ms, scripts de 30 MB

Bases de datos

Servicio Tipo Función sin servidor
DynamoDB Valor-clave + Documento Capacidad bajo demanda, escalamiento automático
Aurora sin servidor Relacional (MySQL/PostgreSQL) Capacidad informática de escalamiento automático
CosmosDB Multimodelo Modo de rendimiento sin servidor
Firestore Documento Escalado automático y sincronización en tiempo real
Neón PostgreSQL sin servidor Ramificación, suspensión automática

Almacenamiento

Servicio Caso de uso
S3/Blob/Almacenamiento en la nube Almacenamiento de archivos, desencadenadores de eventos
ElastiCache sin servidor Almacenamiento en caché en memoria
SQS/almacenamiento en cola Cola de mensajes
EventBridge/Event Grid Autobús de eventos

Patrones de diseño

1. Patrón de abanico

Procese varios elementos en paralelo:

SQS Queue → Lambda → SNS Topic → Lambda (email)
                                 → Lambda (SMS)
                                 → Lambda (push)
                                 → Lambda (logging)

2. Patrón Saga (Transacciones Distribuidas)

// Order saga with compensation
async function createOrder(event) {
  const { orderId, userId, items, total } = event;

  try {
    await reserveInventory(items);
    await processPayment(userId, total);
    await createShipment(orderId);
    await sendConfirmation(userId);

    return { status: 'completed', orderId };
  } catch (error) {
    // Compensating transactions (undo)
    await cancelShipment(orderId);
    await refundPayment(userId, total);
    await releaseInventory(items);

    throw error;
  }
}

3. Patrón de cola de aceleración

Maneje los picos de tráfico almacenando en búfer las solicitudes:

API Gateway → SQS (buffer) → Lambda (process)
                              ↑
                     Process at your own pace

4. Patrón de abastecimiento de eventos

// Store events, derive current state
interface OrderEvent {
  type: 'CREATED' | 'ITEM_ADDED' | 'PAID' | 'SHIPPED' | 'CANCELLED';
  orderId: string;
  timestamp: string;
  data: Record<string, any>;
}

// Function: store event
exports.recordEvent = async (event: OrderEvent) => {
  await dynamo.putItem({
    TableName: 'OrderEvents',
    Item: marshal(event)
  });
  // Don't modify order state directly
};

// Function: rebuild state from events
exports.getOrderState = async (orderId: string) => {
  const events = await queryEvents(orderId);
  return events.reduce((state, event) => applyEvent(state, event), initialState);
};

Monitoreo y observabilidad sin servidor

Registro estructurado

// Structured logging for serverless
const logger = {
  info: (message: string, context?: object) => {
    console.log(JSON.stringify({
      timestamp: new Date().toISOString(),
      level: 'INFO',
      message,
      aws_request_id: context.awsRequestId,
      function_name: context.functionName,
      ...context
    }));
  },
  error: (message: string, error?: Error) => {
    console.error(JSON.stringify({
      timestamp: new Date().toISOString(),
      level: 'ERROR',
      message,
      error_name: error?.name,
      error_message: error?.message,
      stack: error?.stack,
    }));
  }
};

Seguimiento distribuido

// X-Ray tracing
import { AWS } from '@aws-sdk/client-lambda';
import { captureAWS } from 'aws-xray-sdk-core';

const lambda = captureAWS(new AWS.Lambda());

exports.handler = async (event) => {
  const segment = new Segment('process_order');
  // ... function logic with automatic subsegment tracking
};

Paneles de control

Métricas clave a monitorear:

  • Recuento de invocaciones y tasa de error.
  • Duración (p50, p95, p99).
  • Limitaciones (se excedieron los límites de concurrencia).
  • Tasa de arranque en frío.
  • Costo por función.

Cuándo NO utilizar Serverless

Escenario Por qué la tecnología sin servidor no es ideal Alternativa
Procesos de larga duración (>15 min) Tiempo de espera de ejecución Contenedores, máquinas virtuales
Aplicaciones con estado Apátrida por diseño Servicios con estado (WebSocket API, Redis)
Alto tráfico constante (>100 solicitudes/s sostenidas) Los costos exceden la capacidad aprovisionada Contenedores de escalado automático
Requisitos de baja latencia (<10 ms) Arranque en frío por encima Simultaneidad aprovisionada, funciones de borde
Orquestación compleja La composición de funciones es difícil Funciones de paso, flujos de trabajo
Funciones específicas de la plataforma Capacidades de tiempo de ejecución limitadas Acceso completo al sistema operativo (contenedores)

Conclusión

La arquitectura sin servidor es ideal para:

  1. Cargas de trabajo basadas en eventos: procesamiento de archivos, webhooks y notificaciones.
  2. Patrones de tráfico variables: API con carga impredecible.
  3. Creación rápida de prototipos: no es necesario configurar ninguna infraestructura.
  4. Procesamiento en segundo plano: colas, transmisiones, tareas programadas.
  5. Componentes de microservicio: aísla funcionalidades específicas.

Comience con la tecnología sin servidor para:

  • Un nuevo punto final API.
  • Un canal de procesamiento de imágenes.
  • Un trabajo de agregación de datos programado.
  • Un receptor de webhook.

Migre a contenedores cuando:

  • El tráfico se vuelve constante y de gran volumen.
  • La duración de la ejecución excede constantemente los límites.
  • Necesita capacidades específicas a nivel del sistema operativo.
  • El análisis de costos muestra que los contenedores son más baratos.

La tecnología sin servidor no es la respuesta a todo, pero para las cargas de trabajo adecuadas, reduce drásticamente la sobrecarga operativa y el tiempo de desarrollo.

Artículos destacados

6 patrones de programación que aprendí de ingenieros senior
EditorialES
5 minGratis

6 patrones de programación que aprendí de ingenieros senior

TecnologíaCodeProgrammingCoding
0 aplausos
Leer
Crea un asistente privado de notas con IA
DestacadoES
9 minGratis

Crea un asistente privado de notas con IA

Convierte notas Markdown en un asistente consultable sin exponer borradores privados.

TecnologíaGuías de plataformaEscritura con IAAIAutomationData
0 aplausos
Leer
Automatiza la extracción de datos de facturas con OCR
EditorialES
8 minGratis

Automatiza la extracción de datos de facturas con OCR

Crea un flujo que lee facturas, extrae campos y marca valores dudosos para revisión.

TecnologíaArtículos de ingenieríaEscritura con IAAIAutomationData
0 aplausos
Leer

Comentarios

0 comentarios

Todavía no hay comentarios aprobados. Las respuestas nuevas pueden esperar moderación.