web-dev-qa-db-ja.com

KafkaProducer:「コールバック」と返された「未来」の違いは?

KafkaProducer send method は、Futureを返し、Callbackを受け入れます。

送信の完了時にアクションを実行するために、あるメカニズムを他のメカニズムよりも使用することの間には根本的な違いはありますか?

19
Thilo

非同期アプローチ

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

同期に比べてスループットが向上します

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

最初のケースでは確認を待たないので。

また、非同期の方法では順序付けは保証されませんが、同期の方法では-メッセージは確認応答を受信した後にのみ送信されます。

別の違いは、例外の場合の同期呼び出しでは、メッセージの送信を停止できることです例外が発生した直後、一方、2番目のケースでは、何かが間違っていることを発見して何らかのアクションを実行する前にいくつかのメッセージが送信されます。

また、非同期アプローチでは、「送信中」のメッセージの数はmax.in.flight.requests.per.connectionパラメータ。

同期および非同期のアプローチとは別に、Fire and Forgetアプローチを使用できます。これは同期とほぼ同じですが、返されたメタデータを処理せずに、メッセージを送信し、ブローカに到達することを期待します(発生する可能性が最も高いことを認識し、回復可能なエラーの場合にプロデューサが再試行します)が、一部のメッセージが失われる可能性があります。

RecordMetadata rm = producer.send(record);

要約する:

  • Fire and Forget-最速のものですが、一部のメッセージが失われる可能性があります。
  • 同期-最も遅く、メッセージを失う余裕がない場合に使用します。
  • 非同期-中間の何か。
16
streetturtle

リンクしたドキュメントを見ると、FutureとCallbackの主な違いは、「要求が完了しましたが、今は何を」を開始した人にあるようです。質問。

顧客Cとパン屋Bがあるとします。そして、CBに彼をNice cookieにするよう求めています。現在、パン屋が顧客においしいクッキーを返すことができる2つの可能な方法があります。

未来

パン屋はリクエストを受け入れ、顧客に次のように伝えます。 (この契約はFutureです。)

このシナリオでは、顧客はカウンター(Future)をチェックして、パン屋がクッキーを完成したかどうかを確認する責任があります。

ブロッキング顧客はカウンターの近くにとどまり、Cookieがそこに置かれるまで(Future.get())、パン屋が代わりに謝罪をするまで(エラー:Cookieの生地が足りません)、それを見ます。

non-blocking顧客は他の作業を行い、時々、Cookieがカウンター(Future.isDone())で待機していることを確認します。 Cookieの準備ができている場合、顧客はそれを取得します(Future.get())。

Callback

このシナリオでは、顧客はクッキーを注文した後、パン屋に次のように伝えます。私のクッキーの準備ができたら、ここでペットのロボット犬にそれを渡してください、彼はそれをどうするかわかります(このロボットはコールバックです)。

クッキーの準備ができたら、パン屋はクッキーを犬に渡し、飼い主に戻るように言います。パン屋は別の顧客のために次のクッキーを焼き続けることができます。

犬は顧客の元に戻り、クッキーの準備ができていることを顧客に認識させるために、人工の尾を振るようになります。

クッキーがいつ提供されるのか、また準備ができているかどうかを確認するためにパン屋に積極的にポーリングしなかったのに、顧客がどのように考えなかったかに注目してください。

それが2つのシナリオの主な違いです。 「Cookieの準備ができましたが、どうしますか?」を開始する責任は誰にありますか?質問。 Futureでは、顧客は、積極的に待機するか、時々ポーリングすることにより、準備ができたらチェックする責任があります。コールバックの場合、ベイカーは提供された関数にコールバックします。


この答えが、FutureとCalbackが実際に何であるかについてより良い洞察を与えることを願っています。一般的なアイデアが得られたら、特定の各処理がどのスレッドで行われているのかを調べることができます。スレッドがブロックされたとき、またはどの順序ですべてが完了するか。次のようなステートメントを出力するいくつかの簡単なプログラムを作成する:「メインクライアントスレッド:Cookieが受信されました」.

15
Imus

主な違いは、確認応答を待っている呼び出しスレッドをブロックするかどうかです。

次の Future.get() メソッドを使用すると、何らかのアクションを実行する前に送信が完了するまで現在のスレッドがブロックされます。

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

コールバックを使用して何らかのアクションを実行すると、コードはI/Oスレッドで実行されるため、呼び出しスレッドに対してブロックされません。

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

ドキュメント は、プロデューサーで「一般的に」実行されると言っていますが:

通常、コールバックはプロデューサーのI/Oスレッドで実行されるため、適度に高速である必要があります。そうでない場合、他のスレッドからのメッセージの送信が遅延します。ブロッキングまたは計算負荷の高いコールバックを実行する場合は、コールバック本体で独自のエグゼキューターを使用して処理を並列化することをお勧めします。

2
tchambers

The Kafka Producer documentation に基づく私の観察

  • Futureは、同期処理へのアクセスを提供します
  • Futureは確認応答を保証しない場合があります。私の理解では、Callbackは確認後に実行されます
  • Callbackは、完全な非ブロッキング非同期処理へのアクセスを提供します。
    • 同じパーティションでのコールバックの実行順序にも保証があります

同じパーティションに送信されるレコードのコールバックは、順番に実行されることが保証されています。

Future戻りオブジェクトとCallback 'パターン'は2つの異なるプログラミングスタイルを表すと私は考えていますが、これは根本的な違いだと思います。

  • Futureは、Javaの同時実行モデルスタイルを表します。
  • CallbackはJavaのLambdaプログラミングスタイルを表します( Callback は実際に機能インターフェイスの要件を満たしているため)

おそらくFutureスタイルとCallbackスタイルの両方で同様の動作をコーディングすることになる可能性がありますが、一部の使用例では、一方が他方よりも有利であるように見えます。

2
Shiraaz.M