Retour à l'accueil

Erreurs du producteur Kafka dans Node.js : solutions et optimisation

L'article examine les erreurs courantes lors de l'utilisation du producteur Apache Kafka dans Node.js via la bibliothèque KafkaJS : partitionnement incorrect, publication dans des partitions inaccessibles, création inefficace d'instances, problèmes réseau et gestion des messages volumineux. Des solutions pratiques et recommandations sont fournies pour améliorer la fiabilité et les performances.

Comment éviter les erreurs du producteur Kafka dans Node.js ?
Advertisement 728x90

Problèmes et solutions lors de l'utilisation du producteur Kafka en Node.js

Le choix d'une partition pour un message est une étape cruciale qui affecte la répartition de la charge parmi les consommateurs. Une logique de partitionnement incorrecte peut entraîner un déséquilibre et la perte de scalabilité.

Une erreur courante consiste à utiliser une fonction de partitionnement basée sur la division entière de la clé du message (key). Si la clé n'est pas un nombre ou ne peut pas être correctement convertie en entier (par exemple, un ObjectId MongoDB), tous les messages seront envoyés dans une seule partition.

const producer = await kafka.producer(topic, {
  createPartitioner: function () {
    return ({ partitionMetadata, message }: PartitionerArgs) => {
      return partitionMetadata.length
        ? partitionMetadata[Number(message.key) % partitionMetadata.length]?.partitionId || 0
        : 0;
    };
  },
});

Dans ce cas, les consommateurs du groupe ne pourront pas répartir efficacement la charge, car toutes les données sont concentrées dans une seule partition.

Google AdInline article slot

Solution :

  • Valider le type et le format de la clé de partition au niveau du producteur.
  • Mettre en place des métriques pour surveiller les déséquilibres de taille de partition.
  • Utiliser des algorithmes de partitionnement plus fiables, tels que le hachage des clés chaînes.

Publication vers des partitions inexistantes

Les numéros de partition dans un sujet commencent à 0. Si le producteur tente d'envoyer un message à un index de partition supérieur au nombre disponible (par exemple, la partition 1 dans un sujet avec une seule partition), KafkaJS ne lance pas d'erreur. La méthode send() retourne un tableau vide, et le message est effectivement non écrit.

const result = await producer.send({
  topic: 'user_events',
  messages: [
    { key: '2', value: 'user_created', partition: 1 }
  ]
});
console.log(result); // []

Solution :

Google AdInline article slot
  • Créer les sujets et partitions via des fichiers de configuration lors du déploiement pour éviter les erreurs manuelles.
  • Valider la réponse de send() au niveau de l'application. Si le résultat est vide ou contient une erreur (par exemple, errorCode est différent de 0), prendre des mesures : lever une exception, journaliser, envoyer vers un sujet de secours ou envoyer une métrique.
  • Vérifier régulièrement les métadonnées du sujet (liste des partitions disponibles) avant d'envoyer.

Utilisation inefficace du producteur

Créer une nouvelle instance de producteur (kafka.producer()) pour chaque requête ou opération est une erreur fréquente entraînant un surcroît important de coûts. Chaque nouveau producteur établit des connexions réseau lourdes avec les brokers Kafka.

app.post('/send-message', async (request) => {
  const { topic, message } = request.body;
  const producer = kafka.producer(); // Nouvelle instance par requête
  // ...
});

Solution :

  • Utiliser le patron Singleton ou un pool de producteurs. Créer une seule instance de producteur et la réutiliser pour toutes les opérations d'envoi (producer.send()). Cela améliore le débit et réduit la charge sur les brokers.
  • Pour les architectures multi-threadées ou microservices, envisager un client Kafka partagé avec un producteur partagé.

Problèmes de réseau et stratégie de réessai

La connexion réseau entre le producteur et le cluster Kafka peut être instable. Pour améliorer la fiabilité de la livraison des messages :

Google AdInline article slot
  • Configurer la gestion de l'événement request_timeout pour suivre les problèmes réseau.
producer.on('producer.network.request_timeout', (error) => {
  console.error({
    code: 'producer_network_timeout',
    message: error.message,
    data: { stack: error.stack },
  });
})
  • Configurer des mécanismes de réessai (retry) lors de la création du producteur. Par défaut, les réessais sont fixés à 5.
kafka.producer({
  retry: { retries: 10 }
});

Important : Augmenter le nombre de tentatives sans stratégie appropriée (par exemple, sans augmenter les intervalles entre les essais) peut provoquer une charge similaire à un DDoS sur les brokers. Utilisez des configurations avec intervalles croissants (retard exponentiel).

Gestion des messages volumineux

Kafka n'est pas conçu pour gérer des messages de plus de 1 Mo. Envoyer des données importantes (5–10 Mo) entraîne des problèmes sérieux :

  • Rotation fréquente des segments : Avec une taille maximale de segment faible (par exemple, 512 Mo), les messages volumineux déclenchent une rotation rapide, augmentant la charge système.
  • Trafic réseau élevé : La réplication des messages volumineux sur tous les In-Sync Replicas (ISR) augmente la charge réseau.
  • Débit réduit : Le tampon de messages du producteur grandit, augmentant les risques de perte de données et les délais d'attente pour les accusés de réception lorsque acks=-1.
  • Consommation de ressources : Plus de RAM est nécessaire pour le cache de pages du système d'exploitation sur les brokers et pour le JVM Kafka, augmentant la charge CPU due à la collecte de déchets (GC).

Recommandations de taille de message :

  • Utiliser la formule : message.max.bytes = taille moyenne du message * 2, mais inférieure à 1 Mo.
  • Pour les grands fichiers (vidéo, audio, documents), utiliser un stockage externe (par exemple, S3). Envoyer uniquement une référence à l'objet dans le message Kafka.
  • Si des JSON/XML volumineux doivent être envoyés sans stockage externe, le message contient probablement des données redondantes pour différents consommateurs. Considérer la séparation du sujet en plusieurs sujets spécialisés, chacun avec les champs nécessaires minimales.
  • Une alternative, mais plus complexe : découper les messages volumineux en tronçons et les reconstituer côté consommateur.

Points clés

  • Partitionnement : Un calcul incorrect de partition entraîne un déséquilibre de charge et la perte de scalabilité. La validation de la clé et la surveillance des métriques sont obligatoires.
  • Existence de partition : Envoyer vers une partition inexistante ne déclenche pas d'erreur dans KafkaJS, mais le message n'est pas écrit. Valider la réponse de send() est crucial.
  • Efficacité du producteur : Créer un nouveau producteur par requête est coûteux. Utiliser le patron Singleton ou un pool.
  • Réseau et réessais : Configurer la gestion des timeouts réseau et des stratégies de réessai améliore la fiabilité de la livraison.
  • Taille des messages : Envoyer des données supérieures à 1 Mo nuit à la performance du cluster. Utiliser un stockage externe pour les grands fichiers et optimiser la structure des messages.

— Editorial Team

Advertisement 728x90

Lire ensuite