---
title: "Kafka Simulator v1.1: entender la semántica del productor de Kafka"
date: 2026-07-14T00:00:00.000Z
author: "michal"
excerpt: "Kafka Simulator v1.1 añade diez escenarios que cubren el batching, el particionado, la compresión, el backpressure, los reintentos y la idempotencia del productor."
---
¿Qué ocurre después de que un productor de Kafka llama a `send()`?

Suena como una pregunta sencilla. El productor crea un registro, lo envía a Kafka y recibe un acknowledgement.

Sin embargo, entre esos pasos pueden ocurrir bastantes cosas.

El productor puede esperar más registros y crear un batch. Debe elegir una partición. Puede comprimir el batch. Si el broker es lento, el productor puede quedarse sin espacio en el búfer. Si una petición falla, puede reintentarla. Si el reintento tiene éxito después de que la primera petición ya se hubiera escrito, Kafka puede recibir el mismo batch dos veces.

[Kafka Simulator](/kafka-simulator/) v1.1 se centra en esta semántica del productor.

Esta versión añade **10 nuevos escenarios**, con lo que el temario completo llega a **23 de 125 escenarios**.

## ¿Qué incluye la v1.1?

Ocho de los diez escenarios se centran en el productor. Los dos restantes amplían el itinerario de anatomía del log: la lectura hasta el high watermark y el log start offset.

Los escenarios del productor cubren cinco áreas:

- el batching con `linger.ms` y `batch.size`,
- los particionadores del productor,
- la compresión,
- el backpressure con `buffer.memory` y `max.block.ms`,
- los reintentos y la idempotencia.

Veamos cada una de ellas.

## Batching con `linger.ms` y `batch.size`

Un productor de Kafka no envía necesariamente cada registro en una petición separada.

Los registros asignados a la misma partición pueden agruparse en un batch. El productor envía el batch cuando se llena o cuando expira el tiempo de espera configurado.

Aquí es donde dos ajustes del productor se vuelven importantes:

- `batch.size` limita el tamaño de un batch,
- `linger.ms` permite al productor esperar registros adicionales antes de enviarlo.

El compromiso es entre latencia y throughput.

Un batch más grande suele significar menos peticiones y mejor compresión. Sin embargo, esperar a que el batch se llene puede aumentar la latencia de un registro individual.

Los nuevos escenarios hacen visible este comportamiento. Puedes ver cuándo los registros entran en un batch, qué provoca el envío del batch y cómo el cambio de configuración afecta a las peticiones que produce el cliente.

## Particionadores del productor

Antes de que el productor pueda crear un batch específico de una partición, debe seleccionar una partición.

Para los registros con clave, la clave se usa para elegir la partición. Por eso, los registros con la misma clave normalmente se asignan a la misma partición.

Para los registros sin clave, el comportamiento es distinto. El productor puede agrupar los registros usando su estrategia de particionado en lugar de calcular la partición a partir de una clave.

El simulador muestra ambos casos paso a paso:

1. el productor recibe el registro,
2. el particionador selecciona una partición,
3. el registro se añade al batch correspondiente,
4. el batch se envía al líder de esa partición.

Esto facilita ver por qué el particionado afecta tanto al orden como al batching.

## La compresión ocurre por batch

La compresión del productor de Kafka se aplica a los batches de registros, no a cada registro de forma independiente.

Esta distinción importa.

La compresión suele ser más eficaz cuando un batch contiene varios registros similares. Un batch que solo contiene un registro pequeño puede beneficiarse muy poco de la compresión. Un batch más grande con datos repetitivos puede comprimirse de forma mucho más eficiente.

Como resultado, la compresión está conectada con la configuración del batching. Ajustes como `batch.size` y `linger.ms` pueden influir no solo en la frecuencia de las peticiones, sino también en la forma y la compresibilidad de los batches resultantes.

Los nuevos escenarios muestran los tamaños del batch sin comprimir y comprimido, haciendo explícita esta relación.

## Backpressure con `buffer.memory` y `max.block.ms`

¿Qué ocurre cuando una aplicación produce registros más rápido de lo que Kafka puede aceptarlos?

El productor no puede mantener en memoria un número ilimitado de registros sin enviar. Usa un búfer acotado, configurado mediante `buffer.memory`.

Cuando el búfer no tiene espacio disponible, una llamada a `send()` puede bloquearse mientras espera a que se libere memoria.

No esperará para siempre. El tiempo máximo de bloqueo lo controla `max.block.ms`.

Esto nos da dos resultados posibles:

- se envían y confirman suficientes datos, liberando espacio del búfer,
- no se libera espacio antes del timeout y el envío falla.

El simulador rastrea el búfer del productor directamente. Puedes ver cómo se reserva memoria cuando se añaden registros y cómo se libera a medida que se completan las peticiones.

Esto es especialmente útil cuando se combina con un broker lento o una cuota de throughput. En lugar de tratar el backpressure del productor como un problema de configuración abstracto, puedes observar cómo se llena el búfer y ver el envío exacto que se bloquea.

## Reintentos y el problema de los duplicados

Supongamos que el productor envía un batch a un broker.

El broker escribe el batch correctamente, pero el acknowledgement se pierde antes de llegar al productor.

Desde la perspectiva del productor, la petición falló. No puede saber si el broker escribió los datos. Por lo tanto, reintentar es razonable.

Sin embargo, si la primera petición se escribió correctamente, el reintento puede añadir el mismo batch de nuevo.

Este es el problema de los duplicados causado por fallos ambiguos.

El escenario de reintentos muestra ambas peticiones:

1. la petición original llega al broker,
2. el acknowledgement se pierde,
3. el productor reintenta el batch,
4. el broker recibe los mismos registros por segunda vez.

Sin idempotencia, ambas copias pueden añadirse.

## Semántica del productor idempotente

Un productor idempotente permite a Kafka reconocer los batches reintentados.

Kafka asigna una identidad al productor y rastrea los números de secuencia de forma independiente para cada partición. Cuando un batch se reintenta con un número de secuencia que el broker ya ha procesado, el broker puede confirmarlo sin volver a añadir los registros.

La distinción importante es entre un reintento y un duplicado genuino.

Dos registros pueden contener exactamente la misma clave y el mismo valor y aun así ser dos registros distintos enviados intencionadamente por la aplicación. Kafka no debe eliminar tales registros.

La idempotencia deduplica los reintentos del protocolo del productor. No deduplica los datos de la aplicación en función de su contenido.

Los nuevos escenarios muestran:

- los IDs de productor,
- los números de secuencia de partición,
- los reintentos idempotentes exitosos,
- los registros duplicados genuinos,
- la detección de secuencias fuera de orden.

## ¿Por qué importa `max.in.flight.requests.per.connection`?

Un productor puede tener varias peticiones esperando respuesta al mismo tiempo.

Esto mejora el throughput, pero también crea un posible problema de orden.

Supongamos que el productor envía el batch A y luego el batch B. El batch A falla temporalmente, mientras que el batch B tiene éxito. Si A se reintenta después de que B ya se haya escrito, los registros pueden añadirse en un orden diferente.

La idempotencia usa los números de secuencia para detectar un orden inválido.

El simulador muestra esto explícitamente. Puedes ver el número de secuencia esperado por el broker, el número que lleva el batch entrante y el punto en el que el broker rechaza una petición fuera de orden.

## Inspeccionar el estado interno del productor

Los nuevos escenarios se apoyan en gran medida en el **inspector** del simulador, que expone el estado interno de productores y particiones, incluyendo:

- los contadores de reintentos,
- los números de secuencia del productor,
- los números de secuencia del broker,
- la reserva del búfer.

Normalmente, estos valores están ocultos tras las métricas del productor, los logs y el comportamiento del protocolo. En el simulador, se pueden inspeccionar directamente mientras avanzas o retrocedes en un escenario.

## Correcciones en el modelo del productor

Añadir los nuevos escenarios también requirió hacer más preciso el modelo del productor existente.

### Los reintentos se cuentan por batch

Kafka reintenta peticiones de produce que contienen batches de registros.

Por lo tanto, una petición fallida debería consumir un reintento por el batch completo, no un reintento por cada registro que contiene.

El simulador ahora sigue este modelo. Cada registro de un batch fallido se envía de nuevo, mientras que el contador de reintentos avanza una vez.

### La memoria del búfer se libera con precisión

La memoria del búfer del productor ahora se libera a medida que llegan los acknowledgements.

Esto corrige casos en los que el simulador podía reportar backpressure aunque los registros confirmados ya deberían haber liberado su memoria.

Lo mismo se aplica a los timeouts de `max.block.ms`. Cuando un envío bloqueado agota su tiempo, su reserva de búfer se limpia.

### `acks=all` se rastrea por partición

La durabilidad de Kafka se define de forma independiente para cada partición.

Por lo tanto, un productor que escribe en varias particiones debe esperar a que la partición correcta satisfaga sus requisitos de acknowledgement. El progreso en otra partición no debe confirmar una petición no relacionada.

El simulador ahora rastrea este estado por separado para cada partición y topic.

### El reinicio del productor limpia el estado de idempotencia

El broker almacena el estado de deduplicación asociado a un productor idempotente.

Cuando un productor simulado se elimina o se reinicia, este estado también debe eliminarse. De lo contrario, un productor recién creado podría tener sus registros clasificados incorrectamente como reintentos antiguos.

El comportamiento de reinicio ahora limpia el estado correspondiente del lado del broker.

### Retroceder restaura el estado de reintentos

Los escenarios se pueden avanzar y retroceder paso a paso.

Retroceder ahora reconstruye los contadores de reintentos usados durante cada ronda de simulación. Por lo tanto, el estado visible del productor es coherente independientemente de si el escenario avanza o retrocede.

## Mejoras en el terreno de juego

Esta versión también contiene varias correcciones fuera del modelo del productor.

### Rebalanceo de grupos de consumidores

Los grupos de consumidores del terreno de juego recibieron varias correcciones de exactitud:

- el sticky assignor ahora minimiza el movimiento de particiones en lugar de reasignarlas desde cero,
- un miembro estático que permanece ausente más tiempo que `session.timeout.ms` es expulsado como cualquier otro miembro,
- cambiar el número de particiones de un topic ahora desencadena un rebalanceo adecuado sin perturbar el estado de los miembros,
- las particiones nunca se asignan a un miembro que ya no está vivo.

### Configuración de topics y compactación

Kafka nunca reduce el número de particiones de un topic. Reducirlo eliminaría datos y rompería el particionado basado en claves, por lo que `kafka-topics --alter` lo rechaza con `InvalidPartitionsException`.

El terreno de juego ahora sigue la misma regla. Una disminución del número de particiones se rechaza con un error didáctico en lugar de eliminar particiones silenciosamente.

Los topics compactados también se comportan con más precisión:

- un tombstone sobrevive hasta que expira su propia ventana de gracia de `delete.retention.ms`,
- no se puede producir un registro sin clave en un topic compactado,
- con `compact,delete`, la retención por tiempo ahora recupera los registros envejecidos con independencia de la compactación.

### Los enlaces para compartir conservan el escenario completo

El terreno de juego serializa sus acciones en la URL para que un escenario pueda compartirse con otra persona.

El codec ahora incluye todos los cambios de configuración, incluidas las actualizaciones del número de particiones. Un enlace que solicita un tipo de clúster de un paquete de versiones posterior ahora recurre a una topología compatible en lugar de renderizar un clúster inutilizable.

Por lo tanto, abrir un enlace compartido debería recrear el mismo escenario que se construyó originalmente.

### Correcciones de interacción

También se corrigieron varios problemas menores del terreno de juego:

- los identificadores de entidad ya no colisionan después de eliminar y recrear una entidad,
- la colocación de productores funciona correctamente en cuadrículas de brokers más anchas.

### Cabeceras de seguridad

El sitio ahora envía una Content Security Policy y una Permissions Policy.

## ¿Por qué empezar con el productor?

Las garantías de Kafka suelen discutirse desde la perspectiva del broker: replicación, pertenencia al ISR, high watermarks y failover de líder.

Sin embargo, la garantía que observa una aplicación también depende del productor.

¿Qué modo de acknowledgement usa? ¿Reintenta? ¿Está activada la idempotencia? ¿Cuántas peticiones pueden estar en vuelo? ¿Qué ocurre cuando su búfer local se llena?

Estos ajustes determinan si una escritura es rápida, duradera, ordenada, duplicada, bloqueada o rechazada.

Por eso el primer gran paquete de escenarios de Kafka Simulator se centra en el productor.

Una vez que el batching, los acknowledgements, los reintentos y la idempotencia son visibles, los escenarios posteriores sobre replicación, durabilidad y transacciones tienen una base más clara.

Abre el [Kafka Simulator](/kafka-simulator/), selecciona el itinerario del productor y prueba los escenarios de fallo paso a paso.