Skip to content
SP StackPractices
intermediate Por StackPractices

Colas de Mensajes — Inmersión en RabbitMQ, Kafka y SQS

Guía completa sobre colas de mensajes: cuándo usar RabbitMQ, Kafka o SQS. Cubre patrones, throughput, ordenamiento y consideraciones operativas.

Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.

Visión General

Las colas de mensajes son el sistema circulatorio de la arquitectura distribuida. Te permiten desacoplar componentes, manejar picos de tráfico, procesar tareas en segundo plano y construir sistemas resilientes. Sin embargo, elegir la tecnología equivocada o usar patrones incorrectos puede llevar a pérdida de mensajes, procesamiento duplicado o cuello de botella en la capacidad de procesamiento. Esta guía compara tres sistemas principales — RabbitMQ, Kafka y AWS SQS — y cubre patrones, throughput, garantías de ordenamiento y mejores prácticas operativas.

Cuándo Usar

Usa esta guía cuando:

  • Necesitas elegir una solución de colas de mensajes para tu arquitectura
  • Estás experimentando pérdida de mensajes, retraso o problemas de capacidad de procesamiento
  • Necesitas decidir entre entrega al menos una vez, exactamente una vez o en orden

Solución

Comparación de Tecnologías

CaracterísticaRabbitMQKafkaAWS SQS
ModeloCola tradicional (push)Log distribuido (pull)Cola administrada (pull)
OrdenamientoPor cola, no globalPor partición, secuencialFIFO opcional; best-effort por defecto
Throughput~50K msgs/sec por nodo~1M+ msgs/sec por cluster~300 msgs/sec (FIFO); ~3000 (estándar)
PersistenciaMemoria/disco configurablePersistencia compulsiva en discoGestionada por AWS
Modelo de ConsumoMúltiples consumidores compitenMúltiples consumidores leen particionesMúltiples consumidores compiten
Integración CloudAuto-alojado o administradoAuto-alojado o administrado (Confluent, MSK)Servicio AWS nativo
Cuándo UsarEnrutamiento complejo, RPC asíncrono, traducción de protocoloStreaming de eventos, analytics, logsColas simples, serverless, sin infraestructura

Patrones Principales

# Patrón Work Queue con RabbitMQ
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='task_queue', durable=True)

# Publicador
message = {"task": "process_payment", "order_id": "12345"}
channel.basic_publish(
    exchange='',
    routing_key='task_queue',
    body=json.dumps(message),
    properties=pika.BasicProperties(delivery_mode=2)  # persistente
)

# Consumidor
def callback(ch, method, properties, body):
    task = json.loads(body)
    process_payment(task['order_id'])
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_qos(prefetch_count=1)
channel.basic_consume(queue='task_queue', on_message_callback=callback)
channel.start_consuming()
# Consumidor Kafka con manejo de offset
from kafka import KafkaConsumer

consumer = KafkaConsumer(
    'orders',
    bootstrap_servers=['kafka1:9092', 'kafka2:9092'],
    group_id='payment-processors',
    enable_auto_commit=False,
    auto_offset_reset='earliest'
)

try:
    for message in consumer:
        process_order(message.value)
        consumer.commit()  # Commit manual después de procesamiento exitoso
except Exception as e:
    # No hacer commit — el mensaje se reprocesará
    log_error(e)
# Receptor SQS con manejo de visibilidad
import boto3

sqs = boto3.client('sqs')
queue_url = 'https://sqs.us-east-1.amazonaws.com/123456789/orders-queue'

response = sqs.receive_message(
    QueueUrl=queue_url,
    MaxNumberOfMessages=10,
    WaitTimeSeconds=20,
    VisibilityTimeout=300  # 5 minutos para procesar
)

for message in response.get('Messages', []):
    try:
        process_message(message['Body'])
        sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=message['ReceiptHandle'])
    except Exception:
        # El mensaje vuelve a estar visible después del timeout
        pass

Garantías de Entrega

GarantíaRabbitMQKafkaSQS
Al menos una vezSí (ack)Sí (commit de offset)Sí (por defecto)
Exactamente una vezSí (consumidor idempotente + deduplicación publisher)Sí (idempotente con exactly-once semantics)Sí (FIFO + idempotencia)
En ordenSí (una cola)Sí (por partición, una partición = un consumidor)Sí (cola FIFO)
Best-effortSí (sin ack)NoSí (cola estándar)

Explicación

La elección entre colas tradicionales y logs distribuidos depende de si necesitas comunicación o registro de eventos. Las colas tradicionales (RabbitMQ, SQS) son para pasar trabajo entre componentes. Cada mensaje se consume típicamente una vez. Los logs distribuidos (Kafka) son para registrar eventos que múltiples sistemas pueden leer en diferentes velocidades.

El ordenamiento es la restricción más malentendida. Kafka mantiene orden solo dentro de una partición, no globalmente. Si necesitas ordenamiento global, debes usar una sola partición, lo que limita el throughput. SQS FIFO mantiene orden pero limita a 300 mensajes por segundo. RabbitMQ mantiene orden por cola, pero si tienes múltiples consumidores, el ordenamiento de procesamiento no está garantizado.

La idempotencia es la salvaguardia definitiva contra duplicados. Incluso con exactamente-una-vez configurado, fallos de red pueden causar re-entrega. Diseña tus consumidores para ser idempotentes: usa el message_id como clave de deduplicación, o almacena IDs procesados en Redis con TTL.

Variantes

SituaciónTecnología RecomendadaPatrón
Procesamiento de órdenesKafkaTopic de órdenes con partición por customer_id
Procesamiento de imágenesRabbitMQWork queue con prefetch=1 para balanceo de carga
Notificaciones pushSQS + LambdaTrigger Lambda por mensaje para procesamiento serverless
Reprocesamiento de eventosKafkaRebobinar offset para reprocesar un rango de eventos
RPC asíncronoRabbitMQCola de respuesta correlacionada por correlation_id
Agregación de logsKafkaTopic de logs con retención de 30 días

Mejores Prácticas

  1. Siempre diseña consumidores idempotentes; la re-entrega es inevitable en sistemas distribuidos
  2. Usa prefetch bajo (1-5) cuando el tiempo de procesamiento varía mucho entre mensajes
  3. Implementa dead letter queues para mensajes que fallan repetidamente; evita bucles infinitos
  4. Monitorea lag de consumidores como tu métrica principal de salud de cola
  5. Particiona por business key (customer_id, order_id) para mantener datos relacionados juntos

Errores Comunes

  1. Configurar prefetch alto con procesamiento lento; los mensajes se asignan a consumidores ocupados
  2. No establecer timeouts de visibilidad en SQS; los mensajes se re-procesan antes de que termines
  3. Particionar Kafka por timestamp en lugar de business key; los datos relacionados terminan en particiones diferentes
  4. Tratar los logs de Kafka como colas; no borrar eventos procesados de Kafka
  5. Ignorar la capacidad de procesamiento de consumidores; una cola no absorbe picos si tus consumidores son lentos

Preguntas Frecuentes

¿Cómo elijo entre RabbitMQ y Kafka?

RabbitMQ es mejor para comunicación — pasar trabajo, RPC asíncrono, traducción de protocolo, enrutamiento complejo. Kafka es mejor para registro de eventos — múltiples consumidores leyendo el mismo stream, analytics, replay, integración de datos. Si tu use case es “toma este trabajo y hazlo”, elige RabbitMQ. Si es “algo pasó, múltiples sistemas necesitan saberlo”, elige Kafka.

¿Cómo manejo ordenamiento de mensajes en una cola distribuida?

El ordenamiento global y la escalabilidad son mutuamente excluyentes. Si necesitas ambos, particiona por clave de negocio para ordenamiento local, o usa un paso de procesamiento secuencial único para lógica que requiere orden global. Para RabbitMQ, usa una sola cola y un solo consumidor (o múltiples consumidores con prefetch=1). Para Kafka, usa una sola partición (limita throughput) o acepta ordenamiento por partición.

¿Qué hacer cuando un consumidor es más lento que el productor?

Escala los consumidores horizontalmente — más instancias leyendo de la misma cola/topic. Para Kafka, asegúrate de tener suficientes particiones (una partición = un consumidor). Para RabbitMQ, agrega más consumidores (competirán por mensajes). Para SQS, usa más Lambdas o instancias de procesamiento. Si ya escaste la escala horizontal, optimiza el procesamiento: ¿estás haciendo I/O bloqueante? ¿Puedes procesar en batch? ¿Hay una base de datos lenta?