web-dev-qa-db-ja.com

Kafkaストリームでのべき等性と1回限りの違い

idempotence=trueを有効にすると、正確に1回のトランザクションを実現できると理解したことを文書化しました。

べき等性:べき等プロデューサーは、単一のトピックに対してプロデューサーに対して1回だけ有効にします。基本的に、各単一メッセージ送信にはより厳しい保証があり、エラーが発生した場合に重複することはありません

それで、すでにべき等がある場合、なぜKafka Streamに別のプロパティが必要なのですか?べき等と正確に1回の違いは何ですか?

1回だけのプロパティが通常のKafkaプロデューサーで使用できないのはなぜですか?

8
Sandeep

分散環境では、障害はいつでも発生する非常に一般的なシナリオです。 Kafka環境では、ブローカはクラッシュ、ネットワーク障害、処理の失敗、メッセージの発行中の失敗、またはメッセージの消費の失敗などを行う可能性があります。これらの異なるシナリオにより、異なる種類のデータ損失と複製が発生しました。

障害シナリオ

A(Ack Failed):プロデューサーはメッセージを正常に再試行> 1でパブリッシュしましたが、失敗したため確認応答を受信できませんでした。その場合、プロデューサーは同じメッセージを再試行し、重複が発生する可能性があります。

enter image description here

B(プロデューサープロセスはバッチメッセージで失敗しました):プロデューサーは、いくつかの公開された成功で失敗したメッセージのバッチを送信しました。その場合、プロデューサーが再起動すると、バッチからのすべてのメッセージが再び再発行され、Kafkaで重複が発生します。 enter image description here

C(Fire&Forget Failed)プロデューサーは、retry = 0(fire and forget)でメッセージを公開しました。障害が発生した場合、公開は認識されず、次のメッセージが送信されます。これにより、メッセージが失われます。 enter image description here

D(コンシューマはバッチメッセージで失敗しました)コンシューマはKafkaからメッセージのバッチを受信し、手動でオフセットをコミットします( enable.auto.commit = false)。Kafka)にコミットする前にコンシューマーが失敗した場合、コンシューマーはコンシューマー側で複製を複製する同じレコードを再度消費します。

enter image description here

1回限りのセマンティクス

この場合、プロデューサーがメッセージを再送信しようとしても、メッセージがパブリッシュされ、コンシューマーによって1回だけ消費されます。

Kafkaで1回限りのセマンティックを実現するには、以下の3つのプロパティを使用します

  1. enable.idempotence = true(アドレスa、b、c)
  2. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5(プロデューサーは、接続ごとに常に1つの処理中の要求を持ちます)
  3. isolation.level = read_committed(アドレスd)

べき等を有効にする(enable.idempotence = true)

べき等配信により、プロデューサーは、1つのプロデューサーの存続期間中に、データの損失やパーティションごとの順序なしに、トピックの特定のパーティションにKafkaにメッセージを1回だけ書き込むことができます。

"べき等を有効にするには、MAX_IN_FLIGHT_REQUESTS_PER_CONNECTIONが5以下である必要があり、RETRIES_CONFIGが0より大きく、ACKS_CONFIGが「すべて」であることに注意してください。これらの値がユーザーによって明示的に設定されていない場合、適切な値は互換性のない値が設定されている場合、ConfigExceptionがスローされます "

べき等性を達成するためにKafkaは、メッセージの生成中に製品IDまたはPIDと呼ばれる一意のIDとシーケンス番号を使用します。プロデューサーは、一意のPIDでマップされる発行された各メッセージのシーケンス番号を増分し続けます。ブローカーは常に現在のシーケンスを比較します以前のものと同じ番号で、新しいものが前のものよりも+1でない場合は拒否します。これにより、重複を回避し、同時に、メッセージ内で表示が失われた場合に同じ時間になる enter image description here

失敗のシナリオでは、ブローカーはシーケンス番号を以前のものと比較し、シーケンスが増加していない場合、+ 1はメッセージを拒否します。 enter image description here

トランザクション(isolation.level)

トランザクションは、複数のトピックパーティションのデータをアトミックに更新する機能を提供します。トランザクションに含まれるすべてのレコードは正常に保存されるか、まったく保存されません。これにより、処理したデータとともに同じトランザクションでコンシューマーオフセットをコミットできるため、エンドツーエンドの正確に1回限りのセマンティクスが可能になります。

プロデューサーはkafkaへのメッセージの書き込みを待機しません。プロデューサーはbeginTransaction、commitTransaction、abortTransactionを使用します(失敗した場合))コンシューマーは、isolation.levelを使用します。read_committedまたはread_uncommitted

  • read_committed:コンシューマーは常にコミットされたデータのみを読み取ります。
  • read_uncommitted:トランザクションがコミットされるのを待たずに、オフセット順にすべてのメッセージを読み取ります

Isolation.level = read_committedのコンシューマが完了していないトランザクションの制御メッセージに到達すると、プロデューサがトランザクションをコミットまたはアボートするか、トランザクションのタイムアウトが発生するまで、このパーティションからメッセージは配信されません。トランザクションのタイムアウトは、transaction.timeout.ms(デフォルトは1分)の設定を使用してプロデューサーが決定します。

プロデューサーとコンシューマーで1回だけ

生産者と消費者が分かれている通常の状態。プロデューサーは、べき等であると同時にトランザクションを管理する必要があるため、コンシューマーは、isolation.levelを使用してread_committedのみを読み取り、プロセス全体をアトミック操作として実行できます。これにより、プロデューサーが常にソースシステムと同期することが保証されます。プロデューサーのクラッシュやトランザクションの中止でも、常に一貫性があり、メッセージまたはメッセージのバッチを1つの単位として1回公開します。

同じコンシューマは、メッセージまたはメッセージのバッチを1つの単位として1回受信します。

Exactly-Onceでは、ConsumerとともにSemantic Producerが1つのユニットとして動作するアトミック操作として表示されます。パブリッシュして一度に消費されるか、中止されます。

正確に1回Kafka Stream

Kafka StreamはトピックAからのメッセージを消費し、メッセージを処理してトピックBにパブリッシュします。パブリッシュしたら、commit(コミットはほとんどカバーなしで実行)を使用して、すべてのステートストアデータをディスクにフラッシュします。

Kafkaストリーム内で1回だけは、これらの操作がアトミック操作として処理されることを保証する読み取りプロセス書き込みパターンです。Kafkaストリームケータプロデューサー、コンシューマトランザクションはすべて一緒にKafkaストリームには特別なパラメーターprocessing.guaranteeが付属しています。これにより、すべてのパラメーターを個別に処理するのではなく、正確に_onceまたはat_least_onceできます。

Kafka Streamsは、コンシューマーオフセット、ローカルステートストア、ステートストアの変更ログトピック、プロダクションをアトミックに更新し、トピックをまとめて出力します。これらのステップのいずれかが失敗すると、すべての変更がロールバックされます。

processing.guarantee:以下のパラメータを正確に自動的に指定すると、明示的に設定する必要はありません

  1. isolation.level = read_committed
  2. enable.idempotence = true
  3. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5
6
sun007

Kafkaストリームは、end-to-endの観点から1回限りのセマンティクスを提供します(あるトピックから消費し、そのメッセージを処理してから別のトピックに生成します)トピック)。ただし、プロデューサーのべき等属性のみについて言及しました。それは全体像のほんの一部です。

質問を言い換えましょう:

生産者側で1回限りの配信のセマンティクスが既に保証されているのに、消費者側で1回限りの配信のセマンティクスが必要なのはなぜですか?

Answer:正確に1回の配信セマンティクスは、生成ステップだけでなく、処理の完全なフローでもあるためです。正確に1回の配信を意味的に実現するために、生産と消費で満たさなければならないいくつかの条件があります。

これは一般的なシナリオです。プロセスAはトピックTへのメッセージを生成します。同時に、プロセスBはトピックTからのメッセージを消費しようとします。プロセスBが1つのメッセージを2回処理しないようにします。

プロデューサー部分:プロデューサーがメッセージを2回生成しないようにする必要があります。 Kafka Idempotent Producer を使用できます

コンシューマーパーツ:これがコンシューマーの基本的なワークフローです。

  • ステップ1:消費者はKafkaのトピックからメッセージMを正常にプルします。
  • ステップ2:コンシューマーがジョブを実行しようとすると、ジョブは正常に戻ります。
  • ステップ3:コンシューマーは、メッセージのオフセットをKafkaブローカーにコミットします。

上記の手順は、ただの幸せな道です。実際には多くの問題が発生します。

  • シナリオ1:ステップ2のジョブは正常に実行されますが、コンシューマーがクラッシュします。この予期しない状況以降、コンシューマはメッセージのオフセットをまだコミットしていません。コンシューマーが再起動すると、メッセージは2回消費されます。
  • シナリオ2:コンシューマーがステップ3でオフセットをコミットしている間、ハードウェア障害(CPU、メモリ違反など)によりクラッシュします。再起動すると、コンシューマーはオフセットを正常にコミットしたかどうかを知る方法がありません。

多くの問題が発生する可能性があるため、ジョブの実行とコミットオフセットはatomicでなければなりません。できないという意味ではありませんが、正確に1回だけの配信セマンティクスを確実にするために多大な労力が必要です。 Kafkaストリームはエンジニアの仕事を支えます。

次の点に注意してください:Kafkaストリームは「正確に1回のストリーム処理」を提供します。これは、トピックからの消費、具体化を指しますKafkaトピックの中間状態と1つに生成します。アプリケーションが他の外部サービス(データベース、サービス...)に依存している場合、外部依存関係が1回だけを保証できることを確認する必要があります。それらの場合。

TL、DR:フロー全体で1回限りでは、プロデューサとコンシューマ間の協力が必要です。

参照:

12
hqt