Kafkaトピック設定の習得:包括的ガイド

Kafkaトピックのパーティション、レプリケーション、保持、コンパクション、安全な設定変更に関する実践ガイド。

Kafkaトピック設定の習得:包括的ガイド

Kafkaトピック設定は、データの保存、コピー、有効期限、コンパクション、および消費方法を決定します。開発クラスターではしばらくデフォルト設定でKafkaを実行できますが、本番トピックにはより注意が必要です。不適切なパーティション数は、負荷の高いワークロードを妨げる可能性があります。弱いレプリケーションは、ブローカーの障害をデータ損失に変える可能性があります。緩い保持設定はディスクを満たす可能性があります。キーが欠落または一貫性がない場合、コンパクションは予期しない結果をもたらす可能性があります。

Kafkaトピック設定に取り組む有用な方法は、すべての設定を暗記することではありません。実際のシステムが問いかける質問から始めましょう:必要な並列処理の量、データを利用可能にしておく期間、保存できるデータ量、ブローカー障害時の動作、コンシューマーが完全なイベント履歴を必要とするか、キーごとの最新値のみを必要とするか。

トピックはパーティションに分割されます。各パーティションは順序付けられたログです。Kafkaはパーティション内での順序を保持しますが、トピック全体では保持しません。顧客のすべてのイベントを順序通りに処理する必要がある場合は、customer_idなどの安定したキーを使用して、それらのイベントが同じパーティションに配置されるようにします。ランダムにキーを設定すると、より良い分散が得られる可能性がありますが、エンティティごとの順序は失われます。

パーティション数は、後悔する最初の選択の1つです。パーティションが多いほど、コンシューマーの並列処理が可能になります。1つのコンシューマーグループ内では、パーティションは一度に1つのグループメンバーによってのみ消費されるためです。トピックに6つのパーティションがある場合、コンシューマーグループはそのトピックに対して最大6つのコンシューマーをアクティブに使用できます。7番目のコンシューマーを追加しても、他の割り当てられたパーティションがない限り、そのトピックの消費は増加しません。

パーティションが多いとコストもかかります。メタデータ、オープンファイル、レプリケーション作業、リーダー選出作業、ブローカー障害後の回復時間が増加します。非常に多くのパーティション数は、各パーティションのトラフィックが控えめであっても、クラスター操作を遅くする可能性があります。普遍的な最適な数はありません。小さな内部トピックは3つのパーティションで問題ない場合があります。ビジーなイベントストリームは数十のパーティションを必要とする場合があります。非常に大規模なKafkaインストールではさらに多くのパーティションを使用する可能性がありますが、それは習慣ではなく、測定されたスループットと運用能力に基づくべきです。

明示的な設定でトピックを作成します:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-events.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2

トピック名には意図も含めるべきです。eventsdataのような名前は、クラスターが成長すると役に立たなくなります。user-events.v1billing-invoices.v1、またはinventory-adjustments.v1は、将来のオペレーターにストリームが何であるかを伝え、後でスキーマを破壊的に変更する余地を与えます。

レプリケーションファクターは、Kafkaが各パーティションのコピーをいくつ保持するかを制御します。本番環境では、3が一般的なデフォルトです。1つのブローカーが障害を起こしても、別のレプリカが利用可能になるためです。これはプロデューサー設定を無視できることを意味しません。プロデューサーがacks=1を使用する場合、Kafkaはフォロワーがレコードをコピーする前に確認応答する可能性があります。重要なトピックには、レプリケーションファクター3とトピックレベルのmin.insync.replicas=2、およびプロデューサーのacks=allを組み合わせてください。

min.insync.replicasは誤解されることがよくあります。これはレプリカを作成するわけではありません。acks=allの書き込みが成功するために、いくつの同期レプリカが利用可能でなければならないかを指定します。レプリケーションファクター3とmin.insync.replicas=2の場合、トピックは1つのブローカーが利用不可であることを許容できます。同期レプリカが1つだけ残っている場合、Kafkaは安全なコピーが少なすぎるデータを受け入れる代わりに、強い書き込みを拒否する必要があります。

保持設定は、Kafkaが古いログセグメントを削除できるタイミングを決定します。時間ベースの保持は、トピックレベルでretention.msによって制御されます。サイズベースの保持は、retention.bytesによって制御されます。log.retention.msなどの古いブローカーレベルの名前はブローカーのデフォルトです。トピック設定では一般的にretention.msが使用されます。

たとえば、トピックを7日間保持するには:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.ms=604800000

パーティションごとのストレージを制限するには、retention.bytesを使用します:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.bytes=10737418240

retention.bytesは通常、トピック全体のサイズではなく、パーティションごとであることに注意してください。12のパーティションとretention.bytes=10GBのトピックは、レプリケーション前に約120GB、レプリケーションファクター3で約360GBを使用できます。これは、予期しないディスクアラートを引き起こす可能性のある詳細です。

Kafkaはレコードごとではなく、ログセグメントごとにデータを削除します。短い保持期間を設定しても、セグメントが大きい場合、削除は期待した正確な分に行われない可能性があります。segment.bytessegment.msなどのセグメント設定は、Kafkaが新しいセグメントにロールオーバーするタイミングに影響を与え、クローズされたセグメントのみが削除またはコンパクションの対象となります。小さなセグメントはクリーンアップの応答性を高めることができますが、オーバーヘッドが追加されます。

cleanup.policyは、Kafkaが古いデータをどう処理するかを決定します。デフォルトはdeleteで、保持に基づいて古いセグメントを削除します。compactは各キーの最新レコードを保持し、同じキーを持つ古いレコードを最終的に削除します。コンパクションと保持ウィンドウの両方が必要なトピックには、delete,compactも使用できます。

コンパクションは、ユーザープロファイルの更新、フィーチャーフラグの値、アカウント設定、または主キーでキー付けされたデータベース変更イベントなどの状態のようなストリームに役立ちます。すべてのイベントが重要なイベント履歴には適していません。監査ログをコンパクションすると、同じキーの古いイベントが最終的に消える可能性があります。これはコンプライアンスやデバッグにとってはまったく間違っている可能性があります。

コンパクションはキーにも依存します。nullまたは一貫性のないキーを持つコンパクションされたトピックは、クリーンなキー値チェンジログのように動作しません。プロデューサーがユーザー更新をuser_idでキー付けしたり、時にはメールでキー付けしたりする場合、Kafkaは異なるキーとして認識します。それらが同じユーザーを表していると推測することはできません。

圧縮はプロデューサーによって設定でき、トピックはcompression.typeを定義してブローカーの動作を制御できます。一般的な値には、Kafkaのバージョンに応じて、producergzipsnappylz4zstdがあります。多くのチームはトピックをproducerのままにして、プロデューサーの圧縮を標準化します。lz4zstdは一般的な選択肢ですが、正しい答えはCPU予算、メッセージの形状、ネットワーク負荷に依存します。

トピック設定は次のように確認できます:

kafka-configs.sh --describe   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1

そして、パーティションの配置は次のように確認できます:

kafka-topics.sh --describe   --bootstrap-server broker1:9092   --topic user-events.v1

両方のコマンドを使用してください。トピック設定は保持、コンパクション、ISRルールを教えてくれます。トピックの説明はリーダー、レプリカ、ISR状態を教えてくれます。トピックは完璧な設定を持っていても、レプリカが同期していないために不健康な状態になる可能性があります。

一部の変更は簡単です。保持、コンパクションポリシー、min.insync.replicas、およびその他のいくつかのトピック設定は動的に変更できます。一部の変更にはより注意が必要です。パーティション数を増やすことはできますが、簡単なコマンドで安全に減らすことはできません。パーティションを増やすと、パーティショニング計算のターゲットパーティションが増えるため、将来のレコードのキー分散も変更されます。既存のレコードはそのまま残ります。同じキーの新しいレコードは、パーティショナーによっては、増加後に異なるパーティションに送られる可能性があります。変更全体で厳密なキーごとの順序が重要な場合は、慎重に計画してください。

レプリケーションファクターの変更は運用作業です。既存のトピックのレプリカを増やすことは、Kafkaが既存のデータを新しいブローカーにコピーする必要があることを意味します。これは多くのI/Oになる可能性があります。再割り当てツールを使用し、進捗を監視し、必要に応じてスロットルをかけてください。クラスターに十分な余剰容量があることがわかっていない限り、ピークトラフィック時に大規模な再割り当てを開始しないでください。

通常の本番イベントトピックの場合、実用的な開始点は次のようになります:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic payments-authorized.v1   --partitions 24   --replication-factor 3   --config min.insync.replicas=2   --config retention.ms=1209600000   --config cleanup.policy=delete

これは次のことを意味します:並列処理に十分なパーティション、可用性のための3つのコピー、強い書き込みに必要な2つの同期レプリカ、14日間の保持、そしてすべての支払い承認イベントが重要であるためコンパクションなし。

状態トピックの場合、形状は異なります:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-preferences.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2   --config cleanup.policy=compact

そのトピックはユーザーIDでキー付けされるべきです。状態を再構築するコンシューマーは、コンパクションされたログを読み取り、最終的に各ユーザーの最新の値を確認できます。すべての過去の設定変更が永遠に残ることを期待すべきではありません。

最良のトピック設定は、運用が退屈なものです。十分なパーティションがありますが、理由もなく数千ではありません。データの価値に一致するレプリケーションがあります。回復とコンプライアンスのニーズに一致する保持があります。キーが意味がある場合にのみコンパクションを使用します。コードまたはドキュメントで記述されているため、別のエンジニアが推測せずに再作成できます。

有用なレビューの習慣は、トピック設定を選択する前にコンシューマーのストーリーを書き留めることです。誰がこのトピックを読みますか?最初からリプレイする必要がありますか?完全な再構築にはどのくらい時間がかかりますか?ソースシステムは古いデータを再公開できますか?コンシューマーが3日間ダウンした場合、Kafkaはまだ見逃したレコードを保持すべきですか?これらの答えは、デフォルトの7日間設定よりも正直に保持を決定します。

支払いイベントを読み取る不正検出コンシューマーを考えてみてください。6時間ダウンした場合、ほぼ確実にKafkaから追いつきたいでしょう。30日間ダウンした場合、支払いデータベースからの別のバックフィルプロセスを期待するかもしれません。そのトピックは、永遠ではなく、2週間の保持が必要かもしれません。セキュリティ監査トピックは異なる要件を持つ場合があり、おそらく長期保持のためにオブジェクトストレージに送信し、Kafkaはホットなリプレイウィンドウのみを保持します。

メッセージサイズもトピックの議論に含めるべきです。Kafkaは設定されていれば大きなレコードを処理できますが、大きなメッセージはプロデューサー、ブローカー、コンシューマー、レプリケーション、フェッチメモリに影響を与えます。チームがマルチメガバイトのJSONブロブやエンコードされたファイルをトピックに配置し始めた場合、max.message.bytesを上げて終わりにしないでください。ペイロードがKafkaの参照とともにオブジェクトストレージに属するかどうかを尋ねてください。Kafkaは通常、ブロブストアとして機能するのではなく、イベントを移動するのに最適です。

スキーマ進化はトピック設定ではありませんが、トピック設計を形成します。orders.v1などのバージョンサフィックスが付いたトピック名は、破壊的な変更が避けられない場合に逃げ道を提供します。互換性のある変更は、コンシューマーとプロデューサーがスキーマポリシーに従っている場合、同じトピックに留まることができます。破壊的な変更は、1つのチームがプロデューサーを制御しているからといって、同じトピックにこっそり入れるべきではありません。Kafkaはシステムを分離しますが、それは契約が尊重されている場合に限ります。

最後に、トピックの所有権を文書化してください。すべての本番トピックには、所有チーム、期待されるプロデューサー、期待されるコンシューマー、保持理由、データ機密性に関するメモが必要です。これは管理的に聞こえますが、02:00にディスクがいっぱいになり、誰もトピックを短縮、削除、コンパクション、またはスロットルできるかどうかを知らない場合に重要です。優れたトピック設定は、技術的な部分と運用上の記憶の両方です。

トピックを公開する前の最終チェックは、障害シナリオを実行することです。1つのブローカーが消えた場合、プロデューサーはまだ書き込めますか?コンシューマーグループが週末中ダウンした場合、保持はギャップをカバーしますか?プロデューサーが不良データを送信した場合、コンシューマーは安全にスキップ、隔離、またはリプレイできますか?トピックが予想の2倍の速さで成長した場合、どの制限がクラスターを保護しますか:保持時間、保持バイト、クォータ、またはアラート?

クォータは言及する価値があります。トピック設定だけでは、共有クラスターをノイズの多いプロデューサーから保護できないからです。Kafkaは、プロデュースおよびフェッチレートを制限できるクライアントクォータをサポートしています。複数のチームが1つのクラスターを共有する場合、クォータは偶発的なリプレイや暴走プロデューサーがブローカーを圧倒するのを防ぐことができます。これらはアラートと組み合わせて、チームがKafkaを静かに非難するのではなく、スロットルされていることを認識できるようにする必要があります。

削除ポリシーを忘れないでください。一部のクラスターは、事故を防ぐためにブローカーレベルでトピック削除を無効にしています。これは賢明な場合がありますが、放棄されたトピックは制御されたクリーンアッププロセスを通じて処理する必要があることを意味します。毎月または四半期ごとのトピックインベントリレビューは、特に実験が古いトピックを残す開発およびステージングクラスターで、驚くほど多くのディスクを再利用できます。