DEV Community

Cover image for Construyendo un Procesador de Imágenes Escalable con SQS y Lambda
Jehiel Martinez
Jehiel Martinez

Posted on

Construyendo un Procesador de Imágenes Escalable con SQS y Lambda

Las aplicaciones que manejan un alto volumen de imágenes necesitan formas eficientes de procesarlas tan pronto como se suben al sistema. El procesamiento directo puede sobrecargar los servidores y crear cuellos de botella. Por eso, es necesario un enfoque distribuido y escalable para manejar cargas de trabajo variables sin sacrificar el rendimiento.

Click here for the english version

Arquitectura

La solución utiliza una arquitectura serverless y event-driven que garantiza escalabilidad y resistencia:

  1. Las imágenes se suben a un bucket de entrada en S3.
  2. Los eventos de subida ejecutan una función Lambda.
  3. Lambda envía los metadatos a una cola SQS.
  4. Una Lambda de procesamiento consume los mensajes de la cola SQS.
  5. Las miniaturas se generan y se almacenan en el bucket de salida.

Este enfoque desacopla las etapas de subida y procesamiento de imágenes, permitiendo que el sistema maneje picos de carga de manera eficiente.

Diagrama

Servicios AWS Utilizados

  • Amazon S3: Funciona como origen para las imágenes originales y destino para las miniaturas procesadas.
  • Amazon SQS: Actúa como message broker para desacoplar las etapas de subida y procesamiento.
  • AWS Lambda: Proporciona capacidad de cómputo serverless para el manejo de eventos y procesamiento de imágenes.
  • AWS IAM: Gestiona los permisos y asegura el acceso seguro a los recursos de AWS.

Implementación Técnica

Subida de Imágenes

  1. Un usuario sube una imagen al bucket de entrada en S3.
  2. Una notificación de evento de S3 activa la primera función Lambda.
  3. Esta función Lambda construye un mensaje que contiene los metadatos de la imagen (ej: bucketName, key).
  4. Los metadatos se publican en una cola SQS.

Procesamiento

  1. Una segunda función Lambda monitorea constantemente la cola SQS en busca de nuevos mensajes.
  2. Al recibir un mensaje, la función Lambda:
    • Descarga la imagen del bucket de entrada.
    • Procesa la imagen usando la librería Sharp para generar las miniaturas.
    • Sube las miniaturas de regreso al bucket .
  3. Una vez que el proceso termina exitosamente, el mensaje correspondiente se elimina de la cola SQS.

Manejo de Errores

  • Dead Letter Queue (DLQ): Los mensajes que fallan en el procesamiento después de varios intentos se mueven a una DLQ para análisis posterior.
  • CloudWatch Logs: Los logs capturan los pasos detallados del procesamiento e información de errores para debugging.
  • Reintentos Automáticos: Los errores transitorios activan reintentos automáticos basados en las políticas de SQS.

Infraestructura como Código con AWS CDK

Veamos en detalle la implementación de la infraestructura principal en nuestro stack de AWS CDK:

S3 Bucket

const bucket = new Bucket(this, 'AwsSqsThumbnailGeneratorBucket', {
      bucketName: 'sqs-thumbnail-generator-bucket',
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
      versioned: true
    });
Enter fullscreen mode Exit fullscreen mode

Creamos un bucket de S3 con versionamiento habilitado para almacenar imágenes originales y miniaturas generadas. El bucket está configurado para la eliminación automática de objetos para simplificar la eliminación del stack, esto no se recomienda en producción.

Queues

const dlq = new Queue(this, 'AwsSqsThumbnailGeneratorDeadLetterQueue', {
  queueName: 'thumbnail-generator-dlq',
  retentionPeriod: cdk.Duration.days(10)
});

const queue = new Queue(this, 'AwsSqsThumbnailGeneratorQueue', {
  queueName: 'thumbnail-generator-queue',
  visibilityTimeout: cdk.Duration.seconds(60),
  deadLetterQueue: {
    queue: dlq,
    maxReceiveCount: 3
  } 
});
Enter fullscreen mode Exit fullscreen mode

Configuramos dos queues (colas):

Un queue principal para procesar imágenes
Una Dead Letter Queue (DLQ) para manejar intentos fallidos de procesamiento
Los mensajes se mueven a la DLQ después de 3 intentos fallidos

S3 to SQS Integration

bucket.addEventNotification(
  EventType.OBJECT_CREATED, 
  new SqsDestination(queue), 
  {prefix: 'uploads/'}
);
Enter fullscreen mode Exit fullscreen mode

Esta configuración envía automáticamente un mensaje a SQS cada vez que se sube un nuevo archivo al directorio uploads/ en nuestro bucket de S3.

Libreria Sharp

const sharpLayer = new LayerVersion(this, 'SharpLayer', {
      code: Code.fromAsset(path.join(__dirname, './layers/sharp.zip')),
      compatibleRuntimes: [Runtime.NODEJS_LATEST],
      compatibleArchitectures: [Architecture.ARM_64]
    });
Enter fullscreen mode Exit fullscreen mode

Necesitamos la librería Sharp para procesar imágenes. Creamos una Lambda Layer con la librería y la adjuntamos a nuestra función de procesamiento. Esto asegura que la librería esté disponible para la función en tiempo de ejecución.

Esta capa específica está construida para la arquitectura ARM64, que es la arquitectura utilizada por los procesadores AWS Graviton2. Está optimizada para rendimiento y ahorro de costos. Sharp Layer

Thumbnail Generator Lambda

  const generator = new NodejsFunction(this, 'AwsSqsThumbnailGeneratorProcessor', {
      functionName: 'thumbnail-generator-processor',
      runtime: Runtime.NODEJS_LATEST,
      handler: 'handler',
      entry: path.join(__dirname, './functions/thumbnail-generator.ts'),
      layers: [sharpLayer],
      architecture: Architecture.ARM_64,
      timeout: cdk.Duration.seconds(60),
      environment: {
        QUEUE_URL: queue.queueUrl
      }
    });

    generator.addEventSource(new SqsEventSource(queue));
Enter fullscreen mode Exit fullscreen mode

Definimos una función Lambda que procesa mensajes del SQS. La función se activa con nuevos mensajes en la cola y genera miniaturas usando la librería Sharp.

El código de la función está definido en el archivo thumbnail-generator.ts, que es responsable de descargar, procesar y subir imágenes.

IAM Policies

  queue.addToResourcePolicy(new PolicyStatement({
      effect: Effect.ALLOW,
      principals: [new ServicePrincipal('s3.amazonaws.com')],
      actions: ['sqs:SendMessage'],
      resources: [queue.queueArn],
      conditions: {
        ArnLike: {
          'aws:SourceArn': bucket.bucketArn,
        },
      },
    }));
  bucket.grantReadWrite(generator);
  queue.grantConsumeMessages(generator);  
Enter fullscreen mode Exit fullscreen mode

Definimos políticas IAM para permitir que el bucket de S3 envíe mensajes al queue y otorgamos a la función Lambda de procesamiento acceso de lectura/escritura al bucket y permiso para consumir mensajes del queue.

Cómo Utilizarlo

Si quieres probar este proyecto, sigue estos pasos:

  1. Clona el Repositorio: AWS SQS Thumbnail Generator.
  2. Actualiza la Configuración: Modifica los detalles de cuenta y región en el archivo /bin/aws-sqs-thumbnail-generator.ts.
  3. Configura los Tamaños de Miniatura: Ajusta los tamaños en el archivo /functions/thumbnail-generator.ts a tus necesidades.
  4. Despliega la Infraestructura: Utiliza AWS CDK para desplegar los recursos necesarios.
  5. Prueba el Flujo: Sube una imagen al bucket de entrada en S3 y observa cómo se generan y almacenan automáticamente las miniaturas en el bucket de salida.

Conclusión

El AWS SQS Thumbnail Generator es un excelente ejemplo de cómo aprovechar la arquitectura serverless para construir flujos de trabajo escalables, eficientes y resilientes. Al desacoplar procesos y utilizar servicios como SQS, Lambda y S3, este proyecto demuestra cómo manejar tareas intensivas en recursos de manera sencilla.

Este proyecto puede expandirse añadiendo funcionalidades como reconocimiento de imágenes, extracción de metadatos o integración con otros servicios de AWS. Las posibilidades son infinitas, y la escalabilidad y flexibilidad de la arquitectura serverless la convierten en la opción ideal para este tipo de aplicaciones.

Recursos Adicionales

Top comments (0)