Apache Kafkaは、リアルタイムで膨大な量のイベントを処理する能力で知られています。しかし、何百万ものイベントを処理するためには、Kafkaプロデューサーサービスとコンシューマーサービスの両方を実装する際に、特定のベストプラクティスに従う必要があります。
Kafkaを使い始める前にあなたのプロジェクトでKafkaを使用するタイミングを理解しましょう:
- 高ボリュームのイベントストリーム。アプリケーション/サービスがユーザーアクティビティイベント、ウェブサイトのクリックイベント、センサーデータイベント、ログイベント、または株式市場の更新などの継続的なイベントストリームを生成する場合、Kafkaの低遅延で大容量を処理する能力は非常に便利です。
- リアルタイム分析。Kafkaは、データが到着次第すぐに処理する必要があるリアルタイムデータ処理パイプラインの構築に特に役立ちます。Kafkaストリーム、Apache Spark、またはFlinkなどの分析エンジンにデータをストリーミングして、即時の分析や洞察を得たり、ストリームまたはバッチ処理を行うことができます。
- アプリケーションのデカップリング。中央メッセージハブとして機能する際に、アプリケーションの異なる部分をデカップリングし、サービスの独立した開発とスケーリングを可能にし、責任ある分離の原則を促進します。
- システム間のデータ統合。分散システムを統合する際、Kafkaは異なるアプリケーション間でデータを効率的に転送し、信頼できるデータブローカーとして機能します。
他のキューイングシステムとの主な違い
以下は、Apache KafkaがActiveMQ、ZeroMQ、VerneMQなどのシステムと異なる点です:
永続ストレージ
Kafkaは、イベントを分散ログに保存し、システムやノードの障害が発生した場合でもデータをいつでも再生できる能力とデータの永続性を提供します。これは、Redisのようなインメモリストレージに依存する可能性のある従来のメッセージキューとは異なります。
パーティショニング
データはブローカーやトピック間でパーティション化され、大規模なデータストリームの並列処理と高スループットを実現します。これにより、消費者スレッドは個々のパーティションに接続でき、水平スケーラビリティを促進します。
消費者グループ
複数の消費者が同じトピックに登録し、パーティション内の異なるオフセットから読み取ることができるため、異なるチームが異なる目的で同じデータを消費し処理するための重複消費パターンを許可します。いくつかの例は次のとおりです:
- MLチームによって消費されるユーザー活動の疑わしい活動の検出
- 推奨チームによる推奨事項の構築
- 広告チームによる関連広告の生成
Kafka プロデューサーのベストプラクティス
バッチサイズとリンガータイム
batch.size
と linger.ms
を設定することで、Kafka プロデューサー のスループットを向上させることができます。 batch.size
はバッチの最大サイズ(バイト単位)です。 Kafka は、プロデューサーに送信する前にバッチ処理しようとします。
linger.ms
は、プロデューサーがバッチに追加されるメッセージを処理するために待機する最大時間(ミリ秒単位)を決定します。
バッチサイズ
と linger.ms
の設定を行うことで、データを処理システムに送信する前に蓄積されるデータ量を制御することができ、大量のデータを扱う際のスループット向上とレイテンシーの低減に大きく役立ちます。 選択した値に応じてわずかな遅延を導入することもあります。 特に、適切な linger.ms
を持つ大きなバッチサイズは、データ転送効率を最適化できます。
圧縮
別のスループットを向上させる方法は、compression.type
構成を通じて圧縮を有効にすることです。プロデューサーは、データをgzip
、snappy
、またはlz4
で圧縮してブローカーに送信することができます。大量のデータの場合、この構成はネットワーク効率と圧縮オーバーヘッドを助けます。また、帯域幅を節約し、システムのスループットを向上させることができます。さらに、適切なシリアライザーとキーシリアライザーを設定することで、データが消費者と互換性のある形式でシリアル化されることを保証できます。
リトライとアイデンティティ
Kafkaプロデューサーの信頼性を確保するためには、リトライとアイデンティティを有効にする必要があります。retries
を構成することで、指定された試行回数内にブローカーからack
を受信しなかったデータのバッチを自動的に再送信できます。
確認
この構成は、メッセージが正常に送信されたと見なす前にブローカーから必要な確認レベルを制御します。acks
レベルを適切に選択することで、アプリケーションの信頼性を制御できます。この構成の受け入れられる値は以下の通りです。
- 0 – 最速ですが、メッセージの配信が保証されません。
- 1 – メッセージはリーダーブローカーに書き込まれた時点で確認され、基本的な信頼性が提供されます。
- all – メッセージはすべてのレプリカが確認した時点で配信されたと見なされ、高い耐久性が確保されます。
ワークロードに基づく構成チューニング
メッセージ送信率、バッチサイズ、エラーレートなどのメトリクスを追跡して、パフォーマンスのボトルネックを特定することをお勧めします。機能/データの変更や更新に基づいて定期的にプロデューサー設定をチェックして調整してください。
Kafkaコンシューマーのベストプラクティス
コンシューマーグループ
すべてのKafkaコンシューマーはコンシューマーグループに属するべきです。コンシューマーグループには1つ以上のコンシューマーを含めることができます。グループ内でより多くのコンシューマーを作成することで、すべてのパーティションから読み取るスケーリングが可能になり、膨大なデータ量を処理できます。group.id
構成はコンシューマーが属するコンシューマーグループを識別し、同じトピックから消費する複数のコンシューマー間で負荷分散を可能にします。ベストプラクティスはアプリケーション内でコンシューマーグループを簡単に識別できる意味のあるグループIDを使用することです。
オフセットのコミット
アプリケーションがオフセットをコミットするタイミングを制御することで、データ損失を回避できます。オフセットをコミットする方法には、自動と手動の2つがあります。高スループットのアプリケーションでは、より良いコントロールのために手動コミットを検討するべきです。
- auto.offset.reset – トピックを消費し始めるときにコミットされたオフセットがない場合(たとえば、新しいトピックまたはグループに初めて参加するコンシューマの場合)の動作を定義します。 オプションには
earliest
(最初から読む)、latest
(最後から読む)、またはnone
(エラーをスロー)があります。 ほとんどのユースケースでは、新しいコンシューマがグループに参加するときにデータが欠落しないようにするために、「earliest」を選択してください。コンシューマがデータの消費を開始する方法を制御し、コンシューマが再起動されたりグループに追加されたりしたときに適切な動作を確保します。 - enable.auto.commit – 定期的にオフセットを自動的にコミットするように構成するのに役立ちます。一般的には、高い信頼性が不要であり、アプリケーションロジック内でオフセットを手動で確定して、正確な一度だけ処理を確保するように設定します。データ処理に対するより多くの制御を可能にするオフセットのコミットを管理するためのコントロールを提供します。
- auto.commit.interval.ms – interval in milliseconds at which offsets are automatically committed if
enable.auto.commit
is set totrue
. Modify based on your application’s processing time to avoid data loss due to unexpected failure.
Fetch Size and Max Poll Records
This configuration helps control the number of records retrieved in each request, configure the fetch.min.bytes
and max.poll.records
. Increasing this value can help improve the throughput of your applications while reducing CPU usage and reducing the number of calls made to brokers.
- fetch.min.bytes – the minimum number of bytes to fetch from a broker in a single poll request. Set a small value to avoid unnecessary network calls, but not too small to avoid excessive polling. It helps optimize the network efficiency by preventing small, frequent requests.
- fetch.max.bytes – 最大 単一のポーリングリクエストでブローカーから取得するバイト数。利用可能なメモリに基づいて調整し、コンシューマー作業者の過負荷を防ぎます。これにより 単一のポーリングで取得するデータ量が減り、メモリの問題を回避します。
- max.poll.interval.ms – タイムアウトする前にポーリングリクエストがデータを返すのを待つ最大時間。 データが利用できない場合、コンシューマーのハングや遅延を避けるために適切なタイムアウトを設定します。これにより、 コンシューマーがメッセージを待ちすぎて行き詰まるのを防ぎます。(場合によっては、livenessプローブに影響があるとk8sポッドが再起動することがあります)。
パーティション割り当て
これは、グループ内のコンシューマーにパーティション(partition.assignment.strategy
)を割り当てるために使用される戦略です(例:range
、roundrobin
)。ほとんどのシナリオではrange
を使用して、コンシューマー間でパーティションを均等に分配します。これにより グループ内のコンシューマー間でバランスの取れた負荷分散が可能になります。
Kafkaを使用する前に考慮すべき重要な点は次のとおりです:
- 複雑性。Kafkaの実装には、その高度な機能や設定により、パーティション管理やオフセット管理などの分散システムの概念を深く理解することが求められます。
- 監視と管理。Kafkaクラスタの監視および管理を実装することは、高い可用性とパフォーマンスを確保するために重要です。
- セキュリティ。Kafkaトピックを通じて流れる機密データを保護するために、堅牢なセキュリティプラクティスを実装することも重要です。
これらのベストプラクティスを実装することで、Kafkaベースのアプリケーションをスケールさせ、数百万または数十億のイベントを処理できるようになります。ただし、最適な設定はアプリケーションの特定の要件に基づいて異なる場合があることを忘れないでください。
Source:
https://dzone.com/articles/best-practices-for-scaling-kafka-based-workloads