¿Por qué Kafka y no una cola tradicional?
Alejandro Alonso Noguerales
24 mar 2026
01 — Donde lo dejamos
En la Parte 1 vimos el problema: un servidor que hace todo de forma síncrona se bloquea cuando las tareas pesadas crecen. La solución es un broker que separa la recepción del procesamiento. Producer encola, Consumer procesa, el usuario no espera.
Pero hay un detalle que dejamos abierto. Cuando dijimos “broker”, no especificamos cuál. Y resulta que no todos los brokers funcionan igual. Hay una diferencia fundamental entre una cola de mensajería tradicional (RabbitMQ, ActiveMQ, SQS) y un distributed log como Kafka. No es solo una cuestión de rendimiento — es una diferencia de modelo mental.
02 — Dos filosofías distintas
La diferencia clave
En una cola tradicional, el mensaje se destruye cuando el consumidor lo procesa. Una vez leído, desaparece. Es como un buzón: sacas la carta y ya no está.
En Kafka, el mensaje se queda. Aunque lo hayas leído, sigue ahí en disco. Es como un libro de contabilidad: lo lees, pero no arrancas la página. Otros pueden leerlo después, o tú puedes volver a leerlo si algo salió mal.
| Criterio | Cola tradicional (MQ) | Kafka (Distributed Log) |
|---|---|---|
| Persistencia | Efímero. El mensaje se borra tras el ACK del consumidor. | Persistente. El mensaje permanece en disco según la retención configurada. |
| Modelo de entrega | Push. El broker empuja los mensajes al consumidor. | Pull. El consumidor pide mensajes a su propio ritmo. |
| Replay | No. Si necesitas reprocesar, el dato ya no existe. | Sí. Puedes rebobinar el offset y reprocesar todo el histórico. |
| Múltiples lectores | Limitado. Un mensaje va a un solo consumidor (o requiere configuración de fanout). | Nativo. Múltiples consumer groups leen el mismo topic de forma independiente. |
| Orden | Global (una cola) pero pierde orden al escalar. | Garantizado por partición. Cada partición mantiene su orden estricto. |
| Filosofía | Cola de tareas pendientes. | Registro histórico de eventos de negocio. |
Esto no hace que Kafka sea “mejor” que RabbitMQ en abstracto. Son herramientas para problemas distintos. Si solo necesitas desacoplar una tarea pesada y procesarla una vez, una cola tradicional te resuelve bien. Pero cuando tienes múltiples servicios que necesitan reaccionar al mismo evento, cuando necesitas reprocesar datos históricos, o cuando el evento en sí es la fuente de verdad de tu sistema — ahí es donde Kafka cambia las reglas.
03 — La infraestructura: brokers, particiones y réplicas
Para entender por qué Kafka puede hacer todo esto, necesitas ver cómo está construido por debajo. No es un solo servidor con una cola — es un clúster distribuido diseñado para no perder datos.
Antes de nada: adiós Zookeeper
Si has leído sobre Kafka antes, probablemente hayas visto que necesitaba un sistema externo llamado ZooKeeper para coordinarse: elección de controladores, gestión de metadata, configuración del clúster. Eran dos sistemas distribuidos que tenías que desplegar, configurar y monitorizar por separado. Eso hacía que arrancar un Kafka en local o en producción fuera considerablemente más complejo.
Eso ya es historia. Desde Kafka 4.0 (marzo 2025), ZooKeeper ha sido eliminado por completo. Su reemplazo es KRaft (Kafka Raft) — un protocolo de consenso integrado en el propio Kafka que gestiona la metadata como un topic interno. Un solo sistema. La puesta en marcha pasa de “configura un ensemble de ZooKeeper, asegura TLS entre ambos, despliega Kafka apuntando al ZK” a simplemente arrancar Kafka.
¿Qué significa en la práctica? Menos servidores que mantener, un solo sistema que monitorizar, runbooks más simples y despliegues más rápidos. Equipos que han migrado reportan reducciones de ~40% en tiempo de setup de clúster y ~20% en costes de infraestructura al retirar los nodos dedicados a ZooKeeper.
Si estás empezando con Kafka hoy, esto es transparente: KRaft es el modo por defecto y el único disponible. No necesitas saber nada de ZooKeeper. Si tienes un clúster existente en versiones 3.x, la migración a KRaft está bien documentada y es requisito antes de saltar a 4.0.
Broker
Un broker es un nodo servidor de Kafka. En producción siempre tienes varios. Uno actúa como líder para cada partición, y los demás mantienen réplicas. Si el líder cae, una réplica toma el control sin perder un solo mensaje.
Topic y Particiones
Un topic es el canal lógico donde publicas eventos (por ejemplo, booking-events). Cada topic se divide en particiones, que son los segmentos físicos donde se almacenan los datos. Las particiones permiten paralelismo: si tienes 3 particiones, puedes tener 3 consumidores leyendo en paralelo.
Offset: el marcapáginas
Cada mensaje en una partición tiene un número secuencial: el offset. Es como un marcapáginas: el consumidor sabe exactamente por dónde va. Si se cae y reinicia, retoma desde su último offset confirmado. Si necesitas reprocesar datos de hace una semana, mueves el offset hacia atrás.
Lag: cuánto te queda por leer
El lag es la diferencia entre el último mensaje publicado y el último que procesó tu consumidor. Si el lag crece y no se recupera, tu consumidor no da abasto — necesitas más instancias o investigar qué lo frena.
04 — Consumer Groups: el mecanismo de escala
Aquí es donde Kafka se vuelve realmente potente. El Consumer Group es el concepto que permite dos patrones completamente distintos con el mismo topic:
Mismo grupo → Balanceo de carga. Si dos consumidores comparten el mismo group.id, Kafka reparte las particiones entre ellos. Cada mensaje lo procesa solo uno. Esto es escalado horizontal: más instancias, más throughput.
Ej:
group.id = "booking-processor"con 3 instancias → cada una lee 1 partición
Distinto grupo → Broadcast. Si dos consumidores tienen distinto group.id, ambos reciben todos los mensajes. Cada servicio consume de forma independiente sin interferir con el otro.
Ej:
"email-service"y"contabilidad-service"→ ambos leen booking-events completo
Esto es exactamente lo que una cola tradicional no puede hacer de forma nativa. En RabbitMQ necesitas configurar un fanout exchange, publicar el mensaje varias veces, o montar arquitectura extra. En Kafka, el evento se publica una vez y cada consumer group lo lee cuando quiere.
Mejor que explicarlo: pruébalo.
Qué probar
Mismo grupo: Envía varios eventos. Observa cómo cada mensaje va a un solo consumidor (balanceo de carga). Kafka reparte las particiones.
Distintos grupos: Cambia el modo y envía eventos. Ahora ambos consumidores reciben todos los mensajes. Cada servicio consume de forma independiente.
Forzar error: Activa el toggle y envía un evento. El mensaje va directamente a la Dead Letter Queue en lugar de a los consumidores. Así funciona la resiliencia: el flujo principal no se bloquea.
05 — El diseño que importa: ¿cómo organizas tus topics?
Esta fue la discusión real que tuvimos al implementar Kafka. No es una pregunta teórica — define la mantenibilidad de todo tu sistema a largo plazo. Evaluamos dos modelos:
Modelo A — Tópicos por dominio (Event-Driven)
Cada servicio publica en su propio topic, nombrado según la entidad de negocio. El topic contiene hechos: lo que pasó. El productor no sabe quién lo va a leer ni qué va a hacer con eso.
Modelo B — Tópicos por acción (Command-Driven)
En este modelo, los topics se nombran por el consumidor destino: topico-plantillas, topico-log. Los productores envían directamente a la cola de “trabajo pendiente” de cada servicio.
La comparativa real
| Criterio | Modelo A (Dominio) | Modelo B (Acción) |
|---|---|---|
| Filosofía | Event-Driven. El topic contiene hechos. | Command-Driven. El topic contiene órdenes. |
| Acoplamiento | Bajo. El productor no sabe quién consume. | Alto. El productor conoce al consumidor. |
| Nuevo servicio | Se suscribe al topic existente. 0 cambios en productores. | Hay que modificar cada productor para que envíe al nuevo topic. |
| Orden | Garantizado por entidad (partition key = booking ID). | Difícil de garantizar: mezcla de fuentes en un solo topic. |
| Mantenimiento | Centralizado en la lógica del dato. | Disperso en múltiples flujos de salida. |
Decidimos Modelo A. La razón principal: si mañana el departamento de Marketing necesita enviar un SMS con cada nueva reserva, solo tiene que suscribirse a
booking-events. No hay que tocar ni una línea de código en el Servicio de Booking.Kafka debe ser un registro histórico de eventos de negocio, no una cola de tareas efímeras. El Modelo A respeta esa filosofía; el Modelo B la contradice.
El tradeoff real: máquinas de estado
Sería deshonesto presentar el Modelo A como la opción perfecta sin contrapartidas. Hay una que nos impactó directamente: el productor necesita gestionar el ciclo de vida de sus entidades con una máquina de estados.
Cuando publicas hechos en un topic de dominio, tú como productor eres responsable de que la secuencia de eventos tenga sentido. El Servicio de Booking no puede publicar un booking.cancelled si la reserva nunca pasó por booking.confirmed. Necesitas validar las transiciones internamente antes de emitir el evento.
Con el Modelo B esto no es necesario. Si usas tópicos por acción, el productor envía directamente una orden: “genera la plantilla de confirmación”. Es un comando explícito. No hay ambigüedad, no hay secuencia que validar, no hay máquina de estados. El consumidor simplemente ejecuta.
¿Entonces por qué elegimos el Modelo A si añade complejidad?
Porque la máquina de estados ya debería existir en tu servicio de dominio. Una reserva tiene un ciclo de vida con o sin Kafka — si permites cancelar una reserva que nunca se creó, tienes un bug de negocio, no un problema de mensajería. El Modelo A simplemente te obliga a hacerlo explícito. El Modelo B lo esconde, y eso es peor a largo plazo.
El coste extra es real pero acotado: lo pagas una vez en el productor. A cambio, ganas desacoplamiento total del lado del consumidor — que es donde el sistema crece y se vuelve difícil de mantener.
06 — Resiliencia: cuando las cosas fallan
En un sistema distribuido, el fallo no es una excepción — es una certeza. Kafka te da las herramientas para gestionarlo, pero la implementación depende de ti.
Schema Registry. Un servidor que valida que cada mensaje cumpla un contrato estricto (Avro, JSON Schema). Si el servicio de Booking cambia el formato del evento sin avisar, el Schema Registry rechaza el mensaje antes de que entre al topic. Evita errores de deserialización en producción.
Idempotencia. Si un consumer procesa un mensaje y se cae antes de confirmar el offset, Kafka lo reintentará. Tu lógica tiene que soportar recibir el mismo evento dos veces sin duplicar la factura. Solución: validar processId antes de ejecutar la acción.
Dead Letter Queue (DLQ). Cuando un mensaje falla repetidamente (formato corrupto, dependencia caída), lo envías a un topic especial: la DLQ. Ahí queda disponible para inspección manual sin bloquear el flujo principal. Regla: tras N reintentos fallidos → DLQ.
07 — Resumen
Kafka no es una cola de mensajes más rápida. Es un cambio de modelo: tus eventos son la fuente de verdad, persisten, y cada servicio los consume a su ritmo sin interferir con los demás.
Si solo necesitas desacoplar una tarea pesada y procesarla una vez, una cola tradicional te basta. Pero si tu sistema necesita que múltiples servicios reaccionen al mismo evento, que puedas reprocesar históricos, y que la arquitectura escale sin que los productores conozcan a los consumidores — Kafka es la herramienta correcta.
Lo que deberías llevar de este artículo
Cola tradicional = el mensaje se destruye al consumirlo. Push. Un lector. Buena para tareas one-shot.
Kafka = el mensaje persiste. Pull. Múltiples lectores independientes. Replay. Buena para event-driven architecture.
Diseño de tópicos: nombra por dominio (qué pasó), no por acción (quién lo necesita). El productor publica hechos; el consumidor decide qué hacer. Tradeoff: el productor necesita una máquina de estados para validar transiciones — pero esa lógica ya debería existir en tu servicio de dominio.
Resiliencia: Schema Registry para contratos, idempotencia con processId, DLQ con reintentos y backoff exponencial.
KRaft: Desde Kafka 4.0, ZooKeeper ya no existe. Un solo sistema para desplegar, configurar y monitorizar. Si empiezas hoy, la barrera de entrada es mucho más baja.