Alejandría

Busca en Alejandría

Plataformas

Apache Kafka

Log distribuido de eventos, persistente y particionado, para integrar servicios y procesar flujos.

01

En pocas palabras

Plataforma de streaming de eventos que almacena mensajes como un log ordenado, replicado y retenido en el tiempo, del que múltiples consumidores leen de forma independiente.

Qué problema resuelve

Integraciones punto a punto que se multiplican, pérdida de eventos y dificultad para que nuevos consumidores reprocesen el historial.

Cuándo utilizarlo

Arquitecturas orientadas a eventos, CDC, auditoría o pipelines de datos. Ejemplo: publicar cada cambio de estado de un crédito para riesgos, contabilidad y analítica.

02

De la idea a la práctica

Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.

Conceptos

Concepto Descripción
Topic Categoría de eventos (credito-eventos)
Partición Log ordenado e inmutable; unidad de paralelismo y de orden
Offset Posición de un mensaje en la partición
Consumer group Conjunto de consumidores que se reparten las particiones
Réplica / ISR Copias de cada partición; in-sync replicas listas para liderar
Retención Por tiempo, tamaño o compaction (último valor por clave)
KRaft Modo de metadatos sin ZooKeeper; único modo desde Kafka 4.0

Un mismo topic puede tener muchos consumer groups, cada uno con su propio offset: riesgos lee en tiempo real y analítica reprocesa los últimos 30 días sin interferir.

Garantías de entrega

Configuración Efecto
acks=all + min.insync.replicas=2 + factor de réplica 3 El broker confirma solo cuando hay al menos dos copias
enable.idempotence=true (por defecto desde 3.0) Evita duplicados por reintentos del productor
Transacciones + isolation.level=read_committed Exactly-once en flujos leer-procesar-escribir dentro de Kafka
Commit de offset tras procesar Al menos una vez en el consumidor; requiere idempotencia

Exactly-once no se extiende a efectos fuera de Kafka (una base de datos, una API): para eso, idempotencia en el consumidor.

Ejemplo: productor con Spring for Apache Kafka

@Service
class PublicadorEventos {
    private final KafkaTemplate<String, CreditoEvento> kafka;

    PublicadorEventos(KafkaTemplate<String, CreditoEvento> kafka) {
        this.kafka = kafka;
    }

    void publicar(CreditoEvento evento) {
        // clave = id del crédito → todos sus eventos van a la misma partición
        kafka.send("credito-eventos", evento.creditoId(), evento);
    }
}

Para que la publicación sea atómica con la base de datos, usa el transactional outbox en lugar de llamar a send dentro de la transacción de negocio.

Diseño de topics y esquemas

  • Un topic por tipo de entidad o flujo, no por consumidor.
  • Número de particiones según el paralelismo máximo de consumo previsto; aumentar después es posible, pero cambia la asignación de claves.
  • Esquemas versionados (Avro, Protobuf o JSON Schema) en un registro con reglas de compatibilidad (backward por defecto).
  • Dead letter topic para mensajes que fallan repetidamente, con alertas y un proceso de reproceso.

Operación

Monitoriza el consumer lag por grupo y partición: es la señal principal de que un consumidor no da abasto. Kafbat UI facilita inspeccionar topics y grupos. Como servicio gestionado existen Confluent Cloud, Amazon MSK, Aiven y Google Cloud Managed Service for Apache Kafka; en GCP, Pub/Sub es una alternativa más simple cuando no se necesita retención larga ni reprocesar por offset.

Consumidor con reintentos y dead letter topic

@Configuration
class KafkaConfig {
    @Bean
    DefaultErrorHandler manejadorErrores(KafkaTemplate<Object, Object> template) {
        var recuperador = new DeadLetterPublishingRecoverer(template);   // publica en <topic>-dlt
        var backoff = new ExponentialBackOffWithMaxRetries(3);
        backoff.setInitialInterval(500);
        backoff.setMultiplier(2.0);
        var handler = new DefaultErrorHandler(recuperador, backoff);
        handler.addNotRetryableExceptions(ValidacionException.class);    // a la DLT sin reintentar
        return handler;
    }
}

@KafkaListener(topics = "credito-eventos", groupId = "contabilidad")
void procesar(CreditoEvento evento, @Header(KafkaHeaders.RECEIVED_KEY) String clave) {
    contabilidad.registrar(evento);   // idempotente: deduplica por evento.id()
}

Para reintentos largos sin bloquear la partición, Spring Kafka ofrece @RetryableTopic, que reenvía el mensaje a topics de reintento con retardos crecientes.

Configuración del consumidor que conviene entender

Propiedad Efecto
max.poll.records Mensajes por lote; lotes grandes con procesamiento lento provocan rebalanceos
max.poll.interval.ms Tiempo máximo entre polls antes de expulsar al consumidor del grupo
enable.auto.commit Desactivado en Spring por defecto; el commit lo gestiona el contenedor tras procesar
auto.offset.reset earliest o latest cuando el grupo no tiene offset
isolation.level read_committed para no leer mensajes de transacciones abortadas
group.protocol=consumer Nuevo protocolo de rebalanceo (KIP-848), menos interrupciones

Dimensionar particiones

particiones ≥ throughput objetivo / throughput por consumidor
  Ejemplo: 3 000 msg/s objetivo; un consumidor procesa 400 msg/s → al menos 8 particiones
  Margen para crecer: 12–16

El paralelismo máximo de un consumer group es el número de particiones: consumidores adicionales quedan ociosos. Demasiadas particiones aumentan la carga del clúster y el tiempo de recuperación.

Kafka frente a Google Pub/Sub

Aspecto Kafka Pub/Sub
Modelo Log particionado con retención Cola gestionada con suscripciones
Orden Por partición (clave) Por ordering key, opcional
Reproceso Mover el offset a cualquier punto Seek a un instante o snapshot dentro de la retención
Operación Clúster propio o gestionado Sin servidores
Ecosistema Kafka Connect, Streams, registro de esquemas Integración nativa con servicios de GCP

Para un ecosistema de eventos de dominio con muchos consumidores y reproceso frecuente, Kafka; para integración sencilla entre servicios en GCP, Pub/Sub suele bastar.

Criterios de implementación

Define propietario, esquema, retención y política de compatibilidad para cada topic. Prohíbe la creación automática de topics en producción. Trata los eventos como contratos públicos y documenta las decisiones de particionado en un ADR.

Continúa en las fuentes

Documentación oficial para verificar detalles y explorar más.