En un entorno distribuido, la falla es un escenario muy común que puede ocurrir en cualquier momento. En el entorno de Kafka, el agente puede fallar, fallas en la red, fallas en el procesamiento, fallas al publicar mensajes o fallas en el consumo de mensajes, etc. Este escenario diferente introdujo diferentes tipos de pérdida y duplicación de datos.
Escenarios de falla
A (Ack Failed): el mensaje publicado por el productor se realizó correctamente con el reintento> 1 pero no se pudo recibir el acuse de recibo debido a un error. En ese caso, el Productor volverá a intentar que el mismo mensaje podría introducir duplicados.
B (El proceso del productor falló en los mensajes por lotes): el productor que envió el lote de mensajes falló con pocos resultados publicados. En ese caso, y una vez que el productor se reinicie, volverá a publicar todos los mensajes del lote que introducirá duplicados en Kafka.
C (Fire & Forget Failed) Mensaje publicado por el productor con reintento = 0 (disparar y olvidar). En caso de falla publicada, no se dará cuenta y enviará el siguiente mensaje, esto causará la pérdida del mensaje.
D (Error del consumidor en el mensaje por lotes) Un consumidor recibe un lote de mensajes de Kafka y confirma manualmente su desplazamiento (enable.auto.commit = false). Si el consumidor falló antes de comprometerse con Kafka, la próxima vez el Consumidor volverá a consumir los mismos registros que reproducen duplicados en el lado del consumidor.
Semántica exactamente una vez
En este caso, incluso si un productor intenta reenviar un mensaje, esto lleva a que el mensaje sea publicado y consumido por el consumidor exactamente una vez.
Para lograr la semántica Exactamente una vez en Kafka, utiliza debajo de 3 propiedades
- enable.idempotence = true (dirección a, b & c)
- MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5 (El productor siempre tendrá una solicitud en vuelo por conexión)
- isolated.level = read_committed (dirección d)
Habilitar idempotente (enable.idempotence = true)
La entrega idempotente permite al productor escribir mensajes a Kafka exactamente una vez a una partición particular de un tema durante la vida útil de un solo productor sin pérdida de datos y orden por partición.
"Tenga en cuenta que habilitar la idempotencia requiere que MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION sea menor o igual a 5, RETRIES_CONFIG sea mayor que 0 y ACKS_CONFIG sea 'todos'. Si el usuario no establece estos valores explícitamente, se elegirán valores adecuados. establecido, se lanzará una ConfigException "
Para lograr la idempotencia, Kafka usa una identificación única que se llama identificación del producto o PID y número de secuencia mientras produce mensajes. El productor sigue incrementando el número de secuencia en cada mensaje publicado que se asigna con un PID único. El intermediario siempre compara el número de secuencia actual con el anterior y rechaza si el nuevo no es +1 mayor que el anterior, lo que evita la duplicación y al mismo tiempo si se muestra una pérdida mayor en los mensajes
En caso de falla, el agente comparará el número de secuencia con el anterior y si la secuencia no aumenta +1 rechazará el mensaje.
Transacción (nivel de aislamiento)
Las transacciones nos dan la capacidad de actualizar atómicamente los datos en múltiples particiones de temas. Todos los registros incluidos en una transacción se guardarán con éxito, o ninguno de ellos lo será. Le permite confirmar las compensaciones de sus consumidores en la misma transacción junto con los datos que ha procesado, lo que permite una semántica de extremo a extremo exactamente una vez .
El productor no espera para escribir un mensaje en kafka donde el productor usa beginTransaction, commitTransaction y abortTransaction (en caso de falla) El consumidor usa aislamiento.nivel read_committed o read_uncommitted
- read_committed: el consumidor siempre leerá solo los datos confirmados.
- read_uncommitted: lee todos los mensajes en orden de desplazamiento sin esperar a que se confirmen las transacciones
Si un consumidor con aislamiento.level = read_committed llega a un mensaje de control para una transacción que no se ha completado, no entregará más mensajes desde esta partición hasta que el productor confirme o cancele la transacción o se produzca un tiempo de espera de transacción. El productor determina el tiempo de espera de la transacción utilizando la configuración transaction.timeout.ms (valor predeterminado de 1 minuto).
Exactamente una vez en productor y consumidor
En condiciones normales donde tenemos productores y consumidores separados. El productor tiene que administrar las transacciones de forma idempotente y al mismo tiempo para que el consumidor pueda usar el aislamiento. Esto garantiza que el productor siempre se sincronizará con el sistema fuente. Incluso el bloqueo del productor o la transacción cancelada, siempre será coherente y publicará el mensaje o lote de mensaje como unidad una vez.
El mismo consumidor recibirá un mensaje o lote de mensaje como unidad una vez.
En Exactamente una vez, el Productor semántico junto con el Consumidor aparecerán como una operación atómica que operará como una sola unidad. Publique y consuma una vez o sea abortado.
Exactamente una vez en Kafka Stream
Kafka Stream consume mensajes del tema A, procesa y publica mensajes en el Tema B y, una vez publicado, usa commit (el commit se ejecuta principalmente bajo cubierta) para vaciar todos los datos del almacén de estado en el disco.
Exactamente una vez en Kafka Stream hay un patrón de lectura-proceso-escritura que garantiza que estas operaciones se tratarán como operaciones atómicas. Dado que Kafka Stream atiende al productor, al consumidor y a la transacción, Kafka Stream viene con un procesamiento especial de parámetros. Garantía que podría exactamente una vez o al menos una vez, lo que hace que la vida sea fácil de manejar todos los parámetros por separado.
Kafka Streams actualiza atómicamente las compensaciones de los consumidores, las tiendas estatales locales, los temas del registro de cambios de la tienda estatal y los temas de producción para generar temas todos juntos. Si alguno de estos pasos falla, todos los cambios se revierten.
Processing.guarantee: exactamente_una vez que proporciona automáticamente los siguientes parámetros que no necesita establecer explícitamente
- isolated.level = read_committed
- enable.idempotence = true
- MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5