Cuando alguien dice «necesitamos Kafka», la mitad de la sala asiente y la otra mitad finge que sabe de qué se habla. Y es entendible: Kafka se explica casi siempre con jerga —«broker», «topic», «offset», «streaming»— que no dice nada si no entiendes primero el problema que vino a resolver. La idea incómoda es esta: Kafka no es «una cola de mensajes más rápida». Es un cambio en cómo tus sistemas se hablan entre sí. En vez de que un servicio llame a otro y espere respuesta, los servicios publican hechos que ocurrieron y quien quiera se entera cuando pueda. Ese giro —de «pedir» a «enterarse»— es lo que cambia la arquitectura entera. Vamos de a poco.
1. El problema: el espagueti de las llamadas directas
Empecemos por el dolor, no por la solución.
Imagina un e-commerce. Cuando alguien compra, tienen que pasar varias cosas: cobrar, descontar stock, enviar un email, notificar a logística, actualizar analítica, sumar puntos de fidelidad. La forma «natural» de programarlo es que el servicio de Pedidos llame a cada uno:
Esto funciona… hasta que no. Los problemas aparecen solos:
- Acoplamiento: Pedidos tiene que conocer a los 6 servicios, sus URLs, sus formatos. Si agregas uno nuevo (detección de fraude, por ejemplo), tienes que modificar Pedidos.
- Fragilidad: si el servicio de Email está caído, ¿falla toda la compra? ¿Reintenta? ¿Cuántas veces? Cada llamada síncrona es un punto de falla.
- Lentitud: si Pedidos espera respuesta de los 6, la compra es tan lenta como el servicio más lento.
- Se pierde el dato: cuando Analítica estuvo caída media hora, esos eventos de compra se perdieron. No hay forma de «volver a reproducirlos».
El patrón se repite: N servicios que se llaman entre sí producen un grafo de dependencias que crece de forma cuadrática y se vuelve imposible de razonar. A esto se le suele llamar, con cariño, «arquitectura espagueti».
💡 La pregunta clave
2. La idea central: un registro de hechos (el log)
Kafka, en su corazón, es sorprendentemente simple de imaginar: es un cuaderno de bitácora (log) al que solo se le agregan líneas al final, y que muchos pueden leer a su propio ritmo.
Cada línea es un evento: «el pedido 1234 se pagó», «el usuario 88 se registró», «el sensor 5 marcó 40 °C». Los eventos se escriben una vez y se leen muchas veces, cada lector llevando su propia marca de «por dónde voy».
Tres propiedades que hacen la diferencia frente a una cola tradicional:
- No se borra al leer. En una cola clásica (RabbitMQ, SQS), cuando consumes un mensaje, desaparece. En Kafka el evento permanece (según la retención configurada: 7 días, 30, o «para siempre»). Leerlo no lo consume.
- Cada lector tiene su propia posición (offset). Email puede ir por el evento 1000 mientras Analítica recién procesa el 200. No se estorban.
- Se puede «rebobinar». ¿Un servicio nuevo necesita procesar todo el histórico? Empieza desde el offset 0. ¿Un bug corrompió datos? Reprocesas desde ayer. Esto se llama replay y es imposible en una cola que borra al leer.
✅ La analogía que sí funciona
3. La arquitectura: topics, particiones, brokers y consumer groups
Ahora sí, la jerga —pero ya con intuición detrás.
Topics y particiones
Un topic es un canal con nombre: pedidos, pagos, clicks. Es el «cuaderno» del que hablábamos.
Pero un solo cuaderno no escala: si todo se escribe en un único log, un solo servidor tiene que aguantar toda la carga. Por eso Kafka parte cada topic en particiones. Cada partición es un log independiente y ordenado, y pueden vivir en máquinas distintas.
Detalle importante: el orden solo está garantizado dentro de una partición, no en el topic completo. Por eso se usa una key (por ejemplo, user_id): todos los eventos del mismo usuario caen en la misma partición y se procesan en orden. Eventos de usuarios distintos pueden ir en paralelo.
Brokers y el clúster
Un broker es un servidor Kafka. Un clúster es un grupo de brokers que se reparten las particiones. Cada partición se replica en varios brokers (típicamente 3): uno es el líder (recibe escrituras) y los otros son réplicas (copias de respaldo). Si el líder muere, una réplica toma el mando. Así Kafka sobrevive a la caída de máquinas sin perder datos.
Consumer groups: el escalado del lado que lee
Acá está una de las piezas más elegantes. Un consumer group es un conjunto de instancias del mismo servicio que se reparten las particiones para procesar en paralelo.
Regla de oro: Kafka asigna cada partición a UN solo consumidor dentro del grupo. Si tienes 3 particiones y 3 instancias, cada una toma una. Si agregas una 4ª instancia, esa se queda sin trabajo (no hay partición para ella). Si una instancia muere, Kafka reasigna su partición a otra viva (esto se llama rebalanceo).
Esto resuelve dos necesidades a la vez:
- Distintos servicios (grupos distintos) reciben cada uno una copia completa del stream. Email y Analítica ven todos los pedidos.
- Dentro de un servicio, varias instancias (mismo grupo) se reparten la carga para escalar horizontalmente.
4. Cómo se implementa: un vistazo al código
No hace falta escribir un servidor: se produce y se consume con librerías. En Python (con confluent-kafka):
Productor (Servicio de Pedidos):
from confluent_kafka import Producer
import json, time
producer = Producer({"bootstrap.servers": "kafka:9092"})
def publicar_pedido(pedido):
producer.produce(
topic="pedidos",
key=str(pedido["user_id"]), # misma key => misma partición => orden por usuario
value=json.dumps({
"evento": "pedido_pagado",
"pedido_id": pedido["id"],
"monto": pedido["monto"],
"ts": time.time(),
}),
)
producer.flush()Consumidor (Servicio de Email):
from confluent_kafka import Consumer
import json
consumer = Consumer({
"bootstrap.servers": "kafka:9092",
"group.id": "email-service", # el consumer group
"auto.offset.reset": "earliest", # si es nuevo, empieza desde el principio
})
consumer.subscribe(["pedidos"])
while True:
msg = consumer.poll(1.0)
if msg is None:
continue
evento = json.loads(msg.value())
enviar_email_confirmacion(evento) # hace su trabajo
consumer.commit(msg) # marca su offset: "ya procesé hasta acá"Lo esencial: Pedidos no sabe que Email existe. Solo publica un hecho. Email decide suscribirse. Si mañana agregas un servicio de Fraude, escribes otro consumidor con group.id = "fraude-service" y no tocas Pedidos.
⚠️ Detalle que muerde: «al menos una vez»
commit del offset, al reiniciar lo procesará otra vez. Kafka garantiza «at least once» por defecto. Por eso tus consumidores deben ser idempotentes: procesar dos veces el mismo evento no debe cobrar dos veces. Hay modos «exactly once» pero tienen costo y complejidad.5. Cómo cambia la arquitectura: de «pedir» a «enterarse»
Volvamos al e-commerce del inicio, ahora con Kafka en medio.
El cambio de mentalidad es profundo:
| Antes (llamadas directas) | Después (eventos) |
|---|---|
| Pedidos ordena a cada servicio qué hacer | Pedidos anuncia que algo pasó |
| Acoplamiento: Pedidos conoce a todos | Desacoplamiento: nadie conoce a nadie, solo al topic |
| Síncrono: espera a que todos respondan | Asíncrono: publica y sigue |
| Si un servicio cae, la compra falla | Si un servicio cae, el evento lo espera en el log |
| Agregar un servicio = modificar Pedidos | Agregar un servicio = suscribir un consumidor nuevo |
| El dato se pierde si nadie lo recibió | El dato queda en el log y se puede reprocesar |
Esto se conoce como arquitectura orientada a eventos (event-driven). El log de Kafka se vuelve la fuente de la verdad: en vez de que el estado viva escondido en la base de datos de cada servicio, el flujo de hechos es lo primario, y los estados se derivan de él (un patrón relacionado es event sourcing).
💡 No es magia gratis
6. ¿Cuándo Kafka SÍ y cuándo NO?
Kafka es potente, pero no es la respuesta a todo. Un árbol de decisión honesto:
Kafka encaja cuando…
- Varios servicios necesitan reaccionar al mismo evento (fan-out).
- Necesitas reproducir/reprocesar el histórico (nuevos consumidores, corrección de bugs, entrenar modelos).
- Volumen alto y sostenido (millones de eventos, telemetría, clicks, IoT).
- Quieres desacoplar servicios de verdad y que sobrevivan a caídas mutuas.
Kafka es sobre-ingeniería cuando…
- Es una comunicación simple 1 a 1 entre dos servicios → una llamada HTTP o una cola simple.
- El volumen es bajo y no necesitas replay → RabbitMQ o SQS son más fáciles de operar.
- No tienes equipo para operar un clúster (aunque los servicios gestionados —Amazon MSK, Confluent Cloud— reducen mucho ese costo).
🚫 El anti-patrón clásico
cron resolvían. La complejidad de Kafka se paga; que valga la pena depende del problema.7. Cierre: el cambio de chip
Si te llevas una sola idea: Kafka no es una tubería más rápida, es un cambio de quién manda a quién. Pasas de un mundo donde un servicio orquesta y ordena, a uno donde los servicios publican hechos y reaccionan de forma autónoma. Eso te da desacoplamiento, resiliencia y la capacidad de rebobinar el tiempo —a cambio de más piezas móviles y más disciplina en observabilidad.
Para un dev, significa dejar de pensar «¿a quién tengo que llamar?» y empezar a pensar «¿qué hecho estoy anunciando y quién querría enterarse?». Para un arquitecto, significa que el diagrama deja de ser un grafo de flechas entre servicios y se vuelve un río de eventos del que todos beben. Ese río, bien diseñado, es lo que permite que un sistema crezca sin convertirse en espagueti.
Para seguir leyendo
- Apache Kafka — Documentación oficial
- Confluent — «What is Apache Kafka?»
- Amazon MSK — Managed Streaming for Apache Kafka
- Martin Kleppmann — Designing Data-Intensive Applications (capítulos sobre logs y streams)
💡 Nota de transparencia