La clé est-elle requise pour envoyer des messages à Kafka?

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

Actuellement, j'envoie des messages sans clé dans le cadre de messages à clé, est-ce que cela fonctionnera toujours delete.retention.ms? Dois-je envoyer une clé dans le cadre du message? Est-ce bon de rendre la clé dans le cadre du message?

gaurav
la source

Réponses:

172

Les clés sont principalement utiles / nécessaires si vous avez besoin d'un ordre fort pour une clé et que vous développez quelque chose comme une machine à états. Si vous avez besoin que les messages avec la même clé (par exemple, un identifiant unique) soient toujours vus dans le bon ordre, joindre une clé aux messages garantira que les messages avec la même clé iront toujours à la même partition dans une rubrique. Kafka garantit l'ordre au sein d'une partition, mais pas entre les partitions d'une rubrique, donc le fait de ne pas fournir de clé - ce qui entraînera une distribution à tour de rôle sur les partitions - ne maintiendra pas cet ordre.

Dans le cas d'une machine à états, les clés peuvent être utilisées avec log.cleaner.enable pour dédupliquer les entrées avec la même clé. Dans ce cas, Kafka suppose que votre application ne se soucie que de l'instance la plus récente d'une clé donnée et le nettoyeur de journal supprime les anciens doublons d'une clé donnée uniquement si la clé n'est pas nulle. Cette forme de compactage des journaux est contrôlée par la propriété log.cleaner.delete.retention et nécessite des clés.

Sinon, la propriété plus courante log.retention.hours , qui est activée par défaut, fonctionne en supprimant des segments complets du journal qui sont obsolètes. Dans ce cas, les clés ne doivent pas être fournies. Kafka supprimera simplement les morceaux du journal qui sont plus anciens que la période de rétention donnée.

C'est tout pour dire que si vous avez activé le compactage des journaux ou si vous avez besoin d'un ordre strict pour les messages avec la même clé, vous devriez certainement utiliser des clés. Sinon, les clés nulles peuvent fournir une meilleure distribution et éviter les problèmes potentiels de point chaud dans les cas où certaines clés peuvent apparaître plus que d'autres.

Kuujo
la source
Je suis nouveau sur Kafka, c'est la raison pour laquelle je pose tant de questions: Il y a quelques questions à ce sujet: Première question, pouvons-nous consommer le message sur la base de la clé, Actuellement, je consomme le message de MessagAndMetadata mm. ou est-ce bien d'ignorer la clé au moment de la consommation du message. J'utilise l'API grand public de niveau élevé.
gaurav
1
@kuujo Je suppose que cette déduplication concerne uniquement les entrées de journal, elle ne déduplique pas nécessairement les messages sur une file d'attente de sujets?
user1658296
2
@oblivion fait entrer les messages dans la même partition de manière séquentielle est important pour gérer les mises à jour non idemponentes, par exemple le client sélectionne la date de livraison (un message) mais change d'avis plus tard (deuxième message). Si les messages devaient aller vers des partitions différentes, alors l'un ou l'autre des messages peut être traité en premier / dernier, par exemple avec 2 consommateurs consommant de chaque partition. Si les deux messages relatifs à la même livraison vont dans la même partition, ils sont alors traités premier entré premier sorti, donnant la date de livraison finale correcte.
Kunal
3
Les garanties d'ordre ne proviennent pas de la clé mais des messages se trouvant dans la même partition. Le routage des messages vers les partitions ne doit pas nécessairement être basé sur des clés. Vous pouvez spécifier explicitement une partition lors de la création d'unProducerRecord
Malt
2
Je crois comprendre que le client producteur est responsable du choix de la partition ( kafka.apache.org/documentation.html#design_loadbalancing ), qui peut ou non être basée sur la clé. Alors pourquoi dites-vous que les clés sont nécessaires pour commander?
lfk
5

En plus de la réponse acceptée très utile, je voudrais ajouter quelques détails supplémentaires

Partitionnement

Par défaut, Kafka utilise la clé du message pour sélectionner la partition du sujet dans lequel il écrit. Ceci est fait par quelque chose comme

hash(key) % number_of_partitions

S'il n'y a pas de clé fournie, Kafka partitionnera les données de manière aléatoire de manière circulaire.

Commande

Comme indiqué dans la réponse donnée, Kafka a des garanties sur la commande des messages uniquement au niveau de la partition.

Supposons que vous souhaitiez stocker les transactions financières de vos clients dans une rubrique Kafka avec deux partitions. Les messages pourraient ressembler à (clé: valeur)

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}

Comme nous n'avons pas défini de clé, les deux partitions ressembleront probablement à

// 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}

Votre consommateur lisant ce sujet pourrait finir par vous dire que le solde du compte est de 600 à un moment donné bien que cela n'ait jamais été le cas! Simplement parce qu'il lisait tous les messages de la partition 0 avant les messages de la partition 1.

Avec une clé sensée (comme customerId), cela pourrait être évité car le partitionnement serait comme ceci:

// 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}

Compactage du journal

Sans clé dans vos messages, vous ne pourrez pas définir la configuration du sujet cleanup.policysur compacted. Selon la documentation, "le compactage du journal garantit que Kafka conservera toujours au moins la dernière valeur connue pour chaque clé de message dans le journal des données pour une seule partition de rubrique".

Ce paramètre agréable et utile ne sera pas disponible sans aucune clé.

Utilisation des clés

Dans des cas d'utilisation réels, la clé d'un message Kafka peut avoir une énorme influence sur vos performances et la clarté de votre logique métier.

Une clé peut par exemple être utilisée naturellement pour partitionner vos données. Comme vous pouvez contrôler vos consommateurs pour lire à partir de partitions particulières, cela pourrait servir de filtre efficace. En outre, la clé peut inclure des métadonnées sur la valeur réelle du message qui vous aident à contrôler le traitement ultérieur. Les clés sont généralement plus petites que les valeurs et il est donc plus pratique d'analyser une clé au lieu de la valeur entière. En même temps, vous pouvez appliquer toutes les sérialisations et l'enregistrement de schéma comme cela a été fait avec votre valeur également avec la clé.

A noter, il existe également le concept d'en- tête qui peut être utilisé pour stocker des informations, voir documentation .

Mike
la source