web-dev-qa-db-fra.com

KafkaProducer: Différence entre `callback` et retourné` Future '?

La méthode d'envoi de KafkaProducer renvoie à la fois un avenir et accepte un rappel.

Existe-t-il une différence fondamentale entre l'utilisation d'un mécanisme par rapport à l'autre pour exécuter une action à la fin de l'envoi?

19
Thilo

L'approche asynchrone

producer.send(record, new Callback(){
    @Override
    onComplete(RecordMetadata rm, Exception ex){...}
})

vous donne un meilleur débit par rapport à synchrone

RecordMetadata rm = producer.send(record).get();

puisque vous n'attendez pas les remerciements dans le premier cas.

De même, la commande asynchrone n'est pas garantie, tandis que la synchronisation est - le message n'est envoyé qu'après réception de l'accusé de réception.

Une autre différence pourrait être qu'en appel synchrone en cas d'exception, vous pouvez arrêter d'envoyer des messages immédiatement après que l'exception se soit produite, alors que dans le second cas, certains messages seront envoyés avant de découvrir que quelque chose ne va pas et d'effectuer certaines actions .

Notez également qu'en approche asynchrone, le nombre de messages "en vol" est contrôlé par max.in.flight.requests.per.connection paramètre.

Outre les approches synchrones et asynchrones, vous pouvez utiliser l'approche Fire and Forget , qui est presque la même que synchrone, mais sans traiter les métadonnées renvoyées - envoyez simplement le message et espérons qu'il parviendra au courtier (sachant que cela se produira probablement et que le producteur réessayera en cas d'erreurs récupérables), mais il y a une chance que certains messages soient perdus:

RecordMetadata rm = producer.send(record);

Résumer:

  • Fire and Forget - le plus rapide, mais certains messages pourraient être perdus;
  • Synchrone - le plus lent, utilisez-le si vous ne pouvez pas vous permettre de perdre des messages;
  • Asynchrone - quelque chose entre les deux.
16
streetturtle

En regardant la documentation que vous y avez liée, la principale différence entre le futur et le rappel réside dans qui initie la "demande est terminée, quoi maintenant?" question.

Disons que nous avons un client C et un boulanger B. Et C demande à B de lui faire un joli cookie. Il y a maintenant 2 façons possibles pour le boulanger de retourner le délicieux cookie au client.

Futur

Le boulanger accepte la demande et dit au client: Ok, quand j'aurai fini, je placerai votre cookie ici sur le comptoir. (Cet accord est le Future.)

Dans ce scénario, le client est responsable de vérifier le compteur (Future) pour voir si le boulanger a terminé son cookie ou non.

blocage Le client reste près du comptoir et le regarde jusqu'à ce que le cookie y soit placé (Future.get ()) ou que le boulanger y présente des excuses (Erreur: Hors de la pâte à biscuits).

non bloquant Le client fait un autre travail, et vérifie de temps en temps si le cookie l'attend sur le comptoir (Future.isDone ()). Si le cookie est prêt, le client le prend (Future.get ()).

Callback

Dans ce scénario, le client, après avoir commandé son cookie, dit au boulanger: Lorsque mon cookie est prêt, donnez-le à mon chien robot ici, il saura quoi en faire (ce robot est le rappel).

Maintenant, le boulanger lorsque le cookie est prêt donne le cookie au chien et lui dit de retourner chez son propriétaire. Le boulanger peut continuer à cuire le prochain cookie pour un autre client.

Le chien retourne vers le client et commence à remuer sa queue artificielle pour informer le client que son cookie est prêt.

Remarquez comment le client n'avait aucune idée du moment où le cookie lui serait remis, et il n'a pas non plus activement sondé le boulanger pour voir s'il était prêt.

C'est la principale différence entre les 2 scénarios. Qui est responsable du lancement de "votre cookie est prêt, que voulez-vous en faire?" question. Avec le futur, le client est responsable de vérifier quand il est prêt, soit en attendant activement, soit en interrogeant de temps en temps. En cas de rappel, le boulanger rappellera la fonction fournie.


J'espère que cette réponse vous donnera une meilleure idée de ce qu'est réellement un avenir et Calback. Une fois que vous avez eu l'idée générale, vous pouvez essayer de découvrir sur quel thread chaque chose spécifique est gérée. Lorsqu'un thread est bloqué, ou dans quel ordre tout se termine. L'écriture de quelques programmes simples qui impriment des instructions comme: "fil client principal: cookie reçu" pourrait être une façon amusante d'expérimenter cela.

15
Imus

La principale différence est de savoir si vous souhaitez bloquer le thread appelant en attente de l'accusé de réception.

Ce qui suit en utilisant la méthode Future.get () bloquerait le thread actuel jusqu'à ce que l'envoi soit terminé avant d'effectuer une action.

producer.send(record).get()
// Do some action

Lorsque vous utilisez un rappel pour effectuer une action, le code s'exécutera dans le thread d'E/S, il n'est donc pas bloquant pour le thread appelant.

 producer.send(record,
               new Callback() {
                   // Do some action
                   }
               });

Bien que la documentation le dise "généralement" exécuté par le producteur:

Notez que les rappels s'exécutent généralement dans le thread d'E/S du producteur et doivent donc être raisonnablement rapides ou retardent l'envoi de messages à partir d'autres threads. Si vous souhaitez exécuter des rappels bloquants ou coûteux en calcul, il est recommandé d'utiliser votre propre exécuteur dans le corps du rappel pour paralléliser le traitement.

2
tchambers

Mes observations basées sur La Kafka Documentation du producteur :

  • Future vous donne accès au traitement synchrone
  • Future peut ne pas garantir l'accusé de réception. Ma compréhension est qu'un Callback s'exécutera après acquittement
  • Callback vous donne accès à un traitement asynchrone entièrement non bloquant .
    • Il existe également des garanties sur l'ordre d'exécution pour un rappel sur la même partition

Les rappels des enregistrements envoyés à la même partition sont garantis pour s'exécuter dans l'ordre.

Mon autre opinion que l'objet de retour Future et le "pattern" Callback représentent deux styles de programmation différents et je pense que c'est la différence fondamentale:

  • Future représente le style de modèle de concurrence de Java.
  • Callback représente le style de programmation Lambda de Java (car Callback satisfait en fait l'exigence d'une interface fonctionnelle)

Vous pouvez probablement finir par coder des comportements similaires avec les styles Future et Callback, mais dans certains cas d'utilisation, il semble qu'un style puisse être plus avantageux que l'autre.

2
Shiraaz.M