¿Se requiere la clave como parte del envío de mensajes a Kafka?

93
KeyedMessage<String, byte[]> keyedMessage = new KeyedMessage<String, byte[]>(request.getRequestTopicName(), SerializationUtils.serialize(message)); 
producer.send(keyedMessage);

Actualmente, estoy enviando mensajes sin ninguna clave como parte de los mensajes con clave, ¿seguirá funcionando delete.retention.ms? ¿Necesito enviar una clave como parte del mensaje? ¿Es bueno hacer la clave como parte del mensaje?

Gaurav
fuente

Respuestas:

172

Las claves son en su mayoría útiles / necesarias si necesita un orden fuerte para una clave y está desarrollando algo como una máquina de estado. Si necesita que los mensajes con la misma clave (por ejemplo, una identificación única) se vean siempre en el orden correcto, adjuntar una clave a los mensajes garantizará que los mensajes con la misma clave siempre vayan a la misma partición en un tema. Kafka garantiza el orden dentro de una partición, pero no entre las particiones de un tema, por lo que, alternativamente, no proporcionar una clave, lo que resultará en una distribución por turnos entre las particiones, no mantendrá dicho orden.

En el caso de una máquina de estado, las claves se pueden utilizar con log.cleaner.enable para deduplicar entradas con la misma clave. En ese caso, Kafka asume que su aplicación solo se preocupa por la instancia más reciente de una clave determinada y el limpiador de registros elimina los duplicados más antiguos de una clave determinada solo si la clave no es nula. Esta forma de compactación de registros está controlada por la propiedad log.cleaner.delete.retention y requiere claves.

Alternativamente, la propiedad más común log.retention.hours , que está habilitada de manera predeterminada, funciona eliminando segmentos completos del registro que están desactualizados. En este caso, no es necesario proporcionar las claves. Kafka simplemente eliminará fragmentos del registro que sean más antiguos que el período de retención especificado.

Eso es todo, si ha habilitado la compactación de registros o requiere un orden estricto para los mensajes con la misma clave, definitivamente debería usar claves. De lo contrario, las claves nulas pueden proporcionar una mejor distribución y evitar posibles problemas de detección de puntos calientes en los casos en que algunas claves pueden aparecer más que otras.

kuujo
fuente
Soy nuevo en Kafka, esa es la razón por la que hago tantas preguntas: Hay un par de preguntas sobre esto: Primera pregunta, ¿Podemos consumir el mensaje sobre la base de la clave? Actualmente estoy consumiendo mensajes de MessagAndMetadata mm. ¿O está bien ignorar la clave en el momento de consumir el mensaje? Estoy usando la API de consumidor de alto nivel.
gaurav
1
@kuujo Supongo que esta deduplicación es solo para entradas de registro, ¿no elimina necesariamente los mensajes en una cola de temas?
user1658296
2
@oblivion que los mensajes entren en la misma partición secuencialmente es importante para manejar actualizaciones que no son idemponentes, por ejemplo, el cliente selecciona la fecha de entrega (un mensaje) pero cambia de opinión más tarde (segundo mensaje). Si los mensajes fueran a diferentes particiones, entonces cualquiera de los mensajes se puede procesar primero / último, por ejemplo, con 2 consumidores consumiendo de cada partición. Si ambos mensajes relacionados con la misma entrega entran en la misma partición, se procesan primero en entrar, primero en salir, dando la fecha de entrega final correcta.
Kunal
3
Las garantías de orden no provienen de la clave sino de los mensajes que se encuentran en la misma partición. El enrutamiento de mensajes a particiones no tiene por qué estar basado en claves. Puede especificar explícitamente una partición al crear unaProducerRecord
Malt
2
Tengo entendido que el cliente productor es responsable de elegir la partición ( kafka.apache.org/documentation.html#design_loadbalancing ), que puede o no basarse en la clave. Entonces, ¿por qué dice que las llaves son necesarias para realizar pedidos?
lfk
5

Además de la muy útil respuesta aceptada, me gustaría agregar algunos detalles más.

Fraccionamiento

De forma predeterminada, Kafka usa la clave del mensaje para seleccionar la partición del tema en el que escribe. Esto se hace con algo como

hash(key) % number_of_partitions

Si no se proporciona una clave, Kafka dividirá los datos de forma aleatoria en forma de turnos.

Ordenar

Como se indica en la respuesta dada, Kafka tiene garantías sobre el orden de los mensajes solo a nivel de partición.

Supongamos que desea almacenar transacciones financieras para sus clientes en un tema de Kafka con dos particiones. Los mensajes podrían verse como (clave: valor)

null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": -1337}
null:{"customerId": 1, "changeInBankAccount": +200}

Como no hemos definido una clave, las dos particiones probablemente se verán como

// partition 0
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": -1337}

Su consumidor que lea ese tema podría terminar diciéndole que el saldo de la cuenta es de 600 en un momento en particular, ¡aunque ese nunca fue el caso! Solo porque estaba leyendo todos los mensajes en la partición 0 antes que los mensajes en la partición 1.

Con una clave con sentido (como customerId), esto podría evitarse ya que la partición sería así:

// partition 0
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": -1337}
1:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
2:{"customerId": 2, "changeInBankAccount": +100}

Compactación de troncos

Sin una clave como parte de sus mensajes, no podrá establecer la configuración del tema cleanup.policyen compacted. De acuerdo con la documentación, "la compactación de registros asegura que Kafka siempre retendrá al menos el último valor conocido para cada clave de mensaje dentro del registro de datos para una sola partición de tema".

Esta configuración agradable y útil no estará disponible sin ninguna clave.

Uso de llaves

En casos de uso de la vida real, la clave de un mensaje de Kafka puede tener una gran influencia en su rendimiento y la claridad de su lógica empresarial.

Por ejemplo, una clave se puede utilizar de forma natural para particionar sus datos. Como puede controlar a sus consumidores para que lean desde particiones particulares, esto podría servir como un filtro eficiente. Además, la clave puede incluir algunos metadatos sobre el valor real del mensaje que le ayudan a controlar el procesamiento posterior. Las claves suelen ser más pequeñas que los valores y, por lo tanto, es más conveniente analizar una clave en lugar del valor completo. Al mismo tiempo, puede aplicar todas las serializaciones y el registro de esquema como lo hizo con su valor también con la clave.

Como nota, también existe el concepto de encabezado que se puede utilizar para almacenar información, consulte la documentación .

Miguel
fuente