Pub/Sub vs Queues: ¿Cuál elegir para tu aplicación?

Pub/Sub vs Queues: ¿Cuál elegir para tu aplicación?

Las arquitecturas modernas frecuentemente requieren comunicación asíncrona entre componentes y dos patrones comunes para lograr esto son pub/sub y queues de mensajería; este artículo literalmente fue inspirado en una pregunta de twitter y en una explicación que vi en una imagen, pero faltaba la explicación, así es que aquí voy:

Pub/Sub

El patrón pub/sub (publicar/suscribir) involucra enviar mensajes a un tema o canal en lugar de directamente a un receptor. Los publicadores envían mensajes al tema sin conocer a los suscriptores. Luego, los suscriptores reciben los mensajes según su interés en temas específicos.

Características de pub/sub:

  • Comunicación asíncrona uno a muchos - un mensaje puede ser recibido por múltiples suscriptores.
  • Los suscriptores se suscriben a temas explícitamente, abstractando al publicador.
  • Entrega casi en tiempo real tan pronto el mensaje se publica.

Ejemplo en Python con Redis:

import redis

r = redis.Redis(...)

# Publicador
r.publish('noticias', 'Nuevo artículo publicado')  

# Suscriptor 1
sub = r.pubsub()
sub.subscribe('noticias')
sub.parse_response() # ['message', 'noticias', 'Nuevo artículo publicado']

# Suscriptor 2
sub2 = r.pubsub() 
sub2.subscribe('noticias')
sub2.parse_response() # ['message', 'noticias', 'Nuevo artículo publicado']

Pub/sub es útil para notificaciones en tiempo real y comunicación uno a muchos.

Queues

Las queues son colas FIFO donde los productores insertan mensajes y los consumidores los procesan en orden.

Características:

  • Comunicación asíncrona uno a uno - un mensaje se procesa una vez por un consumidor.
  • Desacoplamiento entre productor y consumidor.
  • Retraso entre producir y consumir debido a la cola.
  • Permite poner en cola trabajo para procesar más tarde.

Ejemplo en Python con RabbitMQ:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='tasks')

# Productor
channel.basic_publish(exchange='', routing_key='tasks', body='Enviar email al usuario') 

# Consumidor
def callback(ch, method, properties, body):
    print(" [x] Recibido %r" % body)
    # procesar tarea

channel.basic_consume(queue='tasks', on_message_callback=callback, auto_ack=True)

Las queues son útiles para trabajos en background, nivelar cargas y desacoplar sistemas.

Comparativa

Pub/Sub Queues
Uno a muchos Uno a uno
Tiempo real Retraso
Acoplado Desacoplado
Suscripción explícita Abstracto para consumidores
Redis, Kafka RabbitMQ, Kafka

Otras opciones

Existen múltiples plataformas para implementar pub/sub y queues, cada una con sus capacidades:

  • Redis: simple, rápido, ampliamente utilizado.
  • RabbitMQ: excelente soporte para queues, usado empresarialmente.
  • Kafka: altamente escalable, muy rápido, buen soporte pub/sub y queues.
  • AWS SNS y SQS: servicios de mensajería de AWS, fácil integración.
  • Google Cloud Pub/Sub: servicio de GCP para messaging.
  • Azure Service Bus: opción de Microsoft Azure.

La elección depende de tus necesidades específicas de cada proyecto, y como mencionado anteriormente, mi patrón de comunicación entre aplicaciones es normalmente Bullmq, Rabbitmq y finalmente Kafka, porque para serles sincero, muy pocas veces he utilizado pub/sub.

Y antes de finalizar este artículo, he de mencionar que RabbitMQ con los exchanges tienen una gran similitud al patrón pub/sub, aunque funcionan de forma diferente porque los exchanges reciben el mensaje y lo publican en diferentes queues, es una forma de emular pub/sub "diferente".

Happy coding! :D


Photo by Omar Flores on Unsplash

Jack Fiallos

Jack Fiallos

Te gustó este artículo?