全体として、Kafka プロデューサーは、データを Kafka クラスターに送信するクライアントです。そのコンポーネントを次の図に示します。
基本コンポーネント:
- プロデューサーのメタデータ - プロデューサーの管理に必要なメタデータ: クラスター内のトピックとパーティション、パーティション リーダーとして機能するエージェント ノードなど。
- パーティショナー - 指定されたレコードのパーティションを計算します。
- シリアライザー - キーと値のシリアライザーを記録します。シリアライザーはオブジェクトをバイト配列に変換します。
- プロデューサー インターセプター - レコードを変更する可能性のあるインターセプター。
- レコード アキュムレータ – レコードを蓄積し、トピック パーティションごとにバッチにグループ化します。
- トランザクション マネージャー - トランザクションを管理し、冪等な生成を保証するために必要な状態を維持します。
- 送信者 - Kafka クラスターにデータを送信するバックグラウンド スレッド。
配置Kafka Producer
Kafka プロデューサには、指定する必要がある 3 つのパラメータがあります。
- bootstrap.servers — Kafka クラスターへの初期接続を確立するために使用されるホスト/ポートのペアのリスト。形式: 「ホスト 1:ポート 1、ホスト 2:ポート 2、…」
- key.serializer — org.apache.kafka.common.serialization.Serializer インターフェイスを実装するキー シリアライザーの完全修飾クラス名を表します。
- value.serializer — org.apache.kafka.common.serialization.Serializer インターフェイスを実装する値シリアライザーの完全修飾クラス名を表します。
Kafkaプロセスにデータを送信する
Kafka プロデューサーはメッセージを非同期に送信し、送信結果を表す Future を返します。さらに、ユーザーはオプションで、Kafka ブローカーによってレコードが確認されたときに呼び出されるコールバックを提供できます。単純そうに見えますが、舞台裏では何かが起こっています。
- プロデューサは、設定されたインターセプタのリストにメッセージを配信します。たとえば、インターセプターはメッセージを変更し、更新されたバージョンを返す場合があります。
- シリアライザーはレコードのキーと値をバイト配列に変換します
- 指定しない場合、デフォルトまたは構成されたパーティショナーがトピック パーティションの計算に使用されます。
- レコード アキュムレータは、構成された圧縮アルゴリズムを使用してメッセージをプロデューサー バッチに追加します。
現時点では、メッセージはまだメモリ内にあり、Kafka ブローカーには送信されていません。Record Accumulator は、メモリ内のメッセージをトピックとパーティションごとにグループ化します。
送信側スレッドは、同じブローカーをリーダーとする複数のバッチをリクエストにグループ化し、送信します。この時点で、メッセージは Kafka に送信されます。
送信時間
Kafka プロデューサーには、さまざまなステージで費やす時間を制御するための構成パラメーターが用意されています。
- max.block.ms — メタデータの取得とバッファ割り当ての待機時間
- linger.ms — 追加のレコードが送信されるまでの待機時間
- retry.backoff.ms - 失敗したリクエストを再試行するまでの待機時間
- request.timeout.ms — Kafka ブローカーからの応答を待つ時間
- delivery.timeout.ms — KIP-91 の一部として後で導入され、プロデューサー コンポーネントの内部を調整することなく、保証されたタイムアウト上限をユーザーに提供します
データの永続性
ユーザーは、acks 構成パラメーターを使用して、Kafka に書き込まれるメッセージの永続性を制御できます。許可される値は次のとおりです。
- 0、プロデューサーはブローカーの確認を待ちません
- 1. プロデューサは、すべてのフォロワーを待たずに、パーティション リーダーがメッセージを書き込むのを待つだけです。
- すべての場合、プロデューサーは、同期されたすべてのレプリカがメッセージを確認するまで待機します。これには待ち時間がかかりますが、利用可能な中で最も強力な保証となります。
acks=all を使用する場合、同期レプリカに関して明確にする必要がある微妙な違いがいくつかあります。Kafka 側では、2 つの設定と現在の状態が動作に影響します。
- トピック複製係数
- min.insync.replicas 設定
- リーダー自体を含む、現在同期しているレプリカの数。
min.insync.replicas acks=all によって要求された同期レプリカの最小しきい値を指定します。この要件が満たされない場合、ブローカーはプロデューサーのリクエストを拒否し、書き込みを試行せず、確認を待ちます。以下の表は、考えられるシナリオを示しています。
一時的な障害の間、同期レプリカの数はレプリカの合計数よりも少なくなることがありますが、それが min.insync.replicas 以上である限り、acks=all を指定したリクエストは成功します。
ユーザーは、失敗したリクエストを再送信することで、一時的な障害を軽減し、耐久性を高めることができます。これは、再試行 (デフォルト MAX_INT) とdelivery.timeout.ms (デフォルト 120000)を設定することで実現できます。再試行するとメッセージが重複し、メッセージの順序が変更される可能性があります。これらの副作用は、enable.idempotence=true を設定することで軽減できますが、スループットの低下が伴います。
パーティション
トピック内のメッセージはセクションに編成されています。ユーザーは、メッセージ キーまたはプラグ可能なProducerPartitioner実装を通じてパーティションの割り当てを制御できます。パーティショナーは、partitioner.class 設定を使用して設定できます。これは、org.apache.kafka.clients.Producer.Partitioner インターフェイスを実装する完全修飾クラス名である必要があります。
Kafka は、デフォルトで DefaultPartitioner、RoundRobinPartitioner、UniformStickyPartitioner の 3 つの実装を提供します。
DefaultPartitioner - メッセージ キーが空の場合、現在のパーティションを使用し、次のバッチで変更します。Null 以外のキーの場合、次の式を使用して計算されます: murmur2hash(key) % トピック パーティションの合計 nr。
RoundRobinPartitioner — メッセージ キーを無視して、ラウンドロビン方式ですべてのアクティブなパーティションにメッセージを均等に分散します。パーティションにリーダーとして指定されたブローカーがある場合、そのパーティションはアクティブであるとみなされます。
UniformStickyPartitioner - メッセージ キーを無視し、現在のパーティションを使用し、次のバッチでパーティションを変更します。