Día 23 de 30 Fase 6: Mensajería Asíncrona con Kafka, RabbitMQ, EDA y CQRS

RabbitMQ, Patrones de Mensajería y Comparativa Estratégica con Kafka

Exchanges, Queues, Bindings, Routing Keys, AMQP 0-9-1, Spring AMQP y Cuándo Elegir Cada Uno

Visión de conjunto. Sales entendiendo cómo funciona y cuándo usarlo; dominarlo pide más práctica en un proyecto real.

  • 3.5h de estudio
  • 5 conceptos
  • 3 preguntas
  • 1 katas
RabbitMQAMQPExchangesQueuesSpring AMQPDead Letter Queue
Al terminar este día sabrás 4
  • Enrutar mensajes con exchanges, bindings y routing keys en RabbitMQ.
  • Controlar la entrega con acknowledgements y prefetch.
  • Desviar mensajes fallidos a un Dead Letter Exchange y reintentar con retardo.
  • Elegir con argumentos entre RabbitMQ y Kafka para un caso concreto.

Modelo AMQP: Exchange, Queue, Binding y Routing Key

En RabbitMQ, los productores NUNCA envían mensajes directamente a una cola. Publican en un Exchange (buzón de enrutamiento). El Exchange usa las Bindings (reglas de enrutamiento) y la Routing Key del mensaje para decidir a qué Queue(s) entregar el mensaje. Tipos de Exchange: direct (routing key exacta), fanout (broadcast a todas las colas vinculadas), topic (patrón con comodines * y #), headers (por atributos del header).

En una línea rabbitTemplate.convertAndSend("ordenes.exchange", "orden.creada", evento);

Topología declarada con Spring AMQP java
@Configuration
class RabbitTopologia {

    @Bean
    TopicExchange tareasExchange() {
        return new TopicExchange("tareas");                      // durable por defecto
    }

    @Bean
    Queue notificacionesQueue() {
        return QueueBuilder.durable("tareas.notificaciones").quorum().build();
    }

    @Bean
    Queue auditoriaQueue() {
        return QueueBuilder.durable("tareas.auditoria").quorum().build();
    }

    @Bean
    Binding soloCompletadas(Queue notificacionesQueue, TopicExchange tareasExchange) {
        // tareas.<proyecto>.completada  ->  notificaciones
        return BindingBuilder.bind(notificacionesQueue).to(tareasExchange).with("tareas.*.completada");
    }

    @Bean
    Binding todosLosEventos(Queue auditoriaQueue, TopicExchange tareasExchange) {
        return BindingBuilder.bind(auditoriaQueue).to(tareasExchange).with("tareas.#");
    }
}
Cómo funciona por dentro

En AMQP los productores nunca publican directamente en una cola. Publican en un exchange con una routing key, y el exchange decide a qué colas copiar el mensaje según sus bindings (reglas que unen exchange y cola). Los consumidores leen de las colas.

Hay cuatro tipos de exchange. direct entrega a las colas cuyo binding coincide exactamente con la routing key. topic admite patrones con palabras separadas por puntos: * sustituye una palabra y # cero o más (tareas.*.completada, tareas.#). fanout ignora la clave y copia a todas las colas enlazadas. headers decide por cabeceras del mensaje.

Esta capa de enrutamiento en el broker es la gran fortaleza de RabbitMQ: puedes añadir un nuevo consumidor interesado solo en ciertos eventos creando una cola y un binding, sin tocar al productor.

Permite patrones de mensajería sofisticados (pub/sub, routing selectivo, broadcast) sin modificar el código del productor.

Se conecta con Patrón Pub/SubRoutingDesacoplamiento

Cuatro bloques cronometrados. No pases al siguiente sin tener el resultado esperado.

  1. Bloque 1: Modelo AMQP y Tipos de Exchange (0 - 25 min)

    Qué estudiar. Exchanges direct, fanout, topic y headers. Bindings y Routing Keys.

    Pregunta a responder. ¿Cómo lograr que un mismo evento llegue a 3 servicios diferentes usando un solo exchange?

    Resultado esperado. Diagrama de arquitectura con exchange fanout y 3 colas vinculadas.

  2. Bloque 2: Productor y Consumidor con Spring AMQP (25 - 50 min)

    Qué estudiar. RabbitTemplate, @RabbitListener, Jackson2JsonMessageConverter.

    Pregunta a responder. ¿Cómo garantizar que un mensaje no se pierde si el consumidor falla?

    Resultado esperado. Productor y consumidor funcionales con acknowledge manual.

  3. Bloque 3: Dead Letter Queues y Comparativa Kafka vs RabbitMQ (50 - 80 min)

    Qué estudiar. Configuración de DLX, criterios de selección entre Kafka y RabbitMQ.

    Pregunta a responder. ¿En qué 3 escenarios es mejor Kafka y en qué 3 es mejor RabbitMQ?

    Resultado esperado. Tabla de decisión Kafka vs RabbitMQ según caso de uso.

  4. Cierre y Consolidación (80 - 90 min)

    Qué estudiar. Repaso de las reglas de oro de mensajería asíncrona.

    Pregunta a responder. ¿Por qué la idempotencia es obligatoria en consumidores de mensajes?

    Resultado esperado. Notas consolidadas en la app.

Tres formas de comprobar si lo has entendido, de menos a más exigente: explicarlo con tus palabras, responder preguntas trampa y resolver el reto del tutor.

Explícalo desde cero

Lee cada ficha y explícala en voz alta antes de seguir: si puedes contárselo a alguien que empieza, lo has entendido.

El Exchange como director de orquesta: el productor solo sabe a quién enviar, no quién escucha

Lo que debes entender

El productor publica mensajes a un Exchange con una routing key. No sabe ni le importa cuántas colas están vinculadas ni cuántos consumidores existen. Esto permite añadir o quitar consumidores sin modificar el productor. Es desacoplamiento puro.

Analogía para contarlo

El Exchange es como la centralita de un hotel: tú llamas a "recepción" (routing key) y la centralita redirige la llamada a la habitación correcta. Si cambian la habitación, el sistema de enrutamiento se actualiza sin que tú tengas que saberlo.

Lo que suele explicarse mal

Mostrar ejemplos donde el productor envía directamente a una cola por nombre, acoplando productor y consumidor.

Señal de que aún no lo dominas

Si configuras el productor con el nombre exacto de la cola destino en lugar de con el nombre del exchange y la routing key.

Preguntas trampa

Responde de memoria, en voz alta o por escrito, y después abre la respuesta razonada: lo importante es el porqué, no la palabra exacta.

Nivel 1 (Básico) ¿Qué ocurre si un consumidor de RabbitMQ con acknowledge manual falla al procesar un mensaje y la conexión se cierra antes de enviar el ack o nack? Ver respuesta

Respuesta razonada

Si la conexión o el canal se cierran con mensajes entregados pero sin confirmar, RabbitMQ los considera no procesados y los vuelve a poner en la cola, en su posición original si es posible. Se entregarán a otro consumidor (o al mismo cuando se reconecte) con la marca redelivered=true.

Es la garantía de entrega «al menos una vez»: no se pierde, pero puede procesarse dos veces si el consumidor llegó a hacer su trabajo (por ejemplo, enviar un correo) y cayó justo antes del ack. Por eso los consumidores deben ser idempotentes, por ejemplo registrando el id del mensaje procesado y descartando repetidos.

Qué está evaluando la pregunta

RabbitMQ detecta la desconexión, marca el mensaje como no confirmado y lo reencola para su entrega a otro consumidor disponible (o al mismo cuando se reconecte). Este es el mecanismo de fiabilidad fundamental de AMQP.

Nivel 2 (Intermedio) ¿Por qué un exchange de tipo fanout ignora la routing key del mensaje y un exchange de tipo direct la requiere exacta? Ver respuesta

Respuesta razonada

Porque resuelven problemas distintos. Un fanout es una difusión: su propósito es copiar cada mensaje a todas las colas enlazadas, sin filtrar, así que la routing key no aporta nada y se ignora. Encaja con «todos los interesados deben enterarse», como invalidar cachés en todas las instancias.

Un direct enruta de forma selectiva: compara la routing key del mensaje con la clave de cada binding y solo entrega si coinciden exactamente. Encaja con distribuir trabajo por tipo (pdf, email). Si necesitas algo intermedio, con patrones, usas un exchange topic.

Qué está evaluando la pregunta

Un fanout distribuye el mensaje a TODAS las colas vinculadas al exchange sin importar la routing key. Un direct solo entrega el mensaje a las colas cuyo binding tenga una routing key que coincida EXACTAMENTE con la del mensaje.

Nivel 3 (Entrevista Senior) En un sistema de alta disponibilidad con RabbitMQ en cluster, ¿qué diferencia hay entre una cola clásica, una cola en espejo (mirrored queue) y una cola tipo Quorum Queue? Ver respuesta

Respuesta razonada

Una cola clásica vive en un único nodo: si ese nodo cae, la cola no está disponible y, si se pierde el disco, sus mensajes también. Las colas clásicas en espejo (mirrored) replicaban la cola en varios nodos, pero su algoritmo de sincronización tenía problemas conocidos de pérdida de datos y de rendimiento; quedaron obsoletas y se eliminaron en RabbitMQ 4.0.

Las Quorum Queues son la opción recomendada para datos importantes: se replican en varios nodos con el algoritmo de consenso Raft, un mensaje se confirma cuando lo tiene la mayoría de réplicas, y si cae el líder se elige otro sin perder mensajes confirmados. Son siempre durables y tienen límites de entrega integrados para mensajes envenenados. Su coste es algo más de latencia y de uso de disco.

Qué está evaluando la pregunta

Las colas clásicas viven en un solo nodo; si cae, los mensajes se pierden. Las mirrored queues replican la cola en múltiples nodos pero con un algoritmo de consenso frágil (deprecated). Las Quorum Queues (recomendadas desde RabbitMQ 3.8+) usan el algoritmo Raft para consenso distribuido robusto, garantizando que los mensajes sobrevivan a la caída de nodos sin inconsistencias.

Reto del tutor

Tu equipo discute si usar Kafka o RabbitMQ para un nuevo sistema de procesamiento de pagos. Los requisitos son: (1) Cada pago debe procesarse EXACTAMENTE una vez; (2) Si el servicio de pagos falla, el mensaje debe reenviarse automáticamente; (3) No se necesita historial de pagos; (4) Se procesan ~500 pagos por segundo en hora punta. ¿Qué herramienta recomendarías y por qué?

Lo que una respuesta suele tener bien

Reconoce que RabbitMQ encaja mejor para este caso de uso.

Lo que suele quedarse en la superficie

Decir "Kafka porque es más moderno".

El concepto de fondo que suele faltar

No evaluar que 500 msg/s es tráfico moderado, que no se necesita historial, y que el modelo de cola con ack/nack de RabbitMQ ofrece semántica más simple para "procesamiento exactamente una vez" en un patrón de cola de trabajo punto a punto.

Cómo lo respondería alguien senior en una entrevista

RabbitMQ es la opción más adecuada para este escenario: (1) El patrón es una cola de trabajo punto a punto, no un flujo de eventos multi-consumidor; (2) RabbitMQ ofrece acknowledge manual con requeue/DLX nativo perfecto para reintentos fiables; (3) 500 msg/s está dentro del rango cómodo de RabbitMQ sin necesitar la complejidad de Kafka; (4) "Exactamente una vez" se logra combinando acks manuales con procesamiento idempotente en la base de datos del servicio; (5) No necesitan retención de historial ni reproducción de eventos, que son las fortalezas de Kafka. Kafka añadiría complejidad operativa innecesaria para este patrón.

Proyecto «Pedidos» · paso 23 de 30

Cola de facturas con RabbitMQ

Repartir trabajo pesado entre varios consumidores sin perder tareas.

De qué va el proyecto

El backend de una tienda online: clientes, catálogo de productos y pedidos con sus líneas, pagos y envíos. Empieza como un proyecto Maven con records y termina como un sistema con API REST, seguridad, mensajería, contenedores y observabilidad. Cada paso construye sobre el anterior, así que trabaja siempre en el mismo repositorio.

Qué hacer

  1. Al pagar un pedido, encola una tarea GenerarFactura en RabbitMQ.
  2. Crea un consumidor con acknowledgement manual que simula generar la factura.
  3. Configura un Dead Letter Exchange para las facturas que fallan tres veces.

Está listo cuando

  • Con dos consumidores arrancados, las facturas se reparten entre ellos.
  • Si un consumidor se cae a mitad de una factura, otro la termina.

Katas: ejercicios cortos

Reglas de oro

  • Publica siempre a un Exchange con routing key, nunca directamente a una cola por nombre.
  • Usa acknowledge manual en producción para no perder mensajes ante fallos del consumidor.
  • Configura siempre un Dead Letter Exchange (DLX) para capturar mensajes fallidos.
  • Para tareas puntuales (emails, PDFs), RabbitMQ es más sencillo y adecuado que Kafka.
  • Para streaming de eventos con múltiples consumidores independientes, elige Kafka.
Se guarda automáticamente

Fuentes oficiales

Revisado el . Este día en Markdown