コンソールコマンドを使用した一般的なKafkaコンシューマーラグのトラブルシューティング
強力なコンソールコマンドを使用してKafkaコンシューマーラグを診断する技術を習得しましょう。この包括的なガイドでは、`kafka-consumer-groups.sh`(およびレガシーな`consumer-offset-checker.sh`)を使用したラグの診断、出力の解釈、そしてコンシューマーオフセットを効果的にリセットしてアプリケーションを再同期させる方法を解説します。ベストプラクティスを学び、オフセットリセットの影響を理解し、Kafkaパイプラインを効率的かつ信頼性の高い状態に保つための実践的な例とアクション可能な手順を提供します。Kafkaオペレーターや開発者にとって不可欠なリソースです。
コンソールコマンドを使用した一般的なKafkaコンシューマーラグのトラブルシューティング
コンシューマーラグは、パイプラインが遅いと感じたときにほとんどのKafkaオペレーターが最初に確認する数値ですが、最も誤解されやすい数値の1つでもあります。グループが100万件のラグを示す理由は、ダウンストリームのAPIがタイムアウトしている場合、デプロイメントで半数のコンシューマーがオフラインになっている場合、1つのパーティションが他よりホットになっている場合、あるいはアプリケーションが正常で計画された一時停止後に単に追いついている場合など、さまざまです。コマンドはシンプルです。その判断がインシデントの勝敗を分けます。
このガイドでは、ラグインシデント時に私が使用するコマンドラインパスに焦点を当てます。グループを記述し、パーティションを比較し、コンシューマーが生きているか確認し、ラグが増加しているか減少しているかを判断し、その後にのみオフセットリセットを検討します。オフセットリセットは時には必要ですが、遅いコンシューマーの治療法ではありません。作業をスキップするか、再実行するかのどちらかです。パフォーマンス修正ではなく、運用上の決定として扱ってください。
Kafkaコンシューマーラグの理解
Kafkaでは、メッセージはトピックに整理され、さらにパーティションに分割されます。パーティション内の各メッセージには、順次不変のオフセットが割り当てられます。コンシューマーは、現在の位置(コミットされたオフセットとも呼ばれる)を維持することでパーティションからメッセージを読み取ります。Kafkaブローカーは各パーティションのログエンドオフセットを追跡します。これはパーティションに追加された最新のメッセージのオフセットを表します。
コンシューマーラグ = ログエンドオフセット - コミットされたオフセット
基本的に、ラグは特定のパーティションのログの先頭に対してコンシューマーが遅れているメッセージの数です。ストリーミングシステムではある程度のラグは自然で予想されますが、一貫して増加するラグや過度に大きいラグは問題を示しています。
高いコンシューマーラグが懸念される理由:
- データ処理の遅延:アプリケーションがデータを処理する速度が遅すぎる可能性があり、リアルタイム分析や重要なビジネスオペレーションに影響を与えます。
- リソースの枯渇:コンシューマーが追いつくのに苦労している可能性があり、CPU、メモリ、またはネットワーク使用率が高くなります。
- 古いデータ:ラグのあるコンシューマーからデータを受け取るダウンストリームシステムは、古い情報で動作します。
- 保持ポリシーの問題:ラグがトピックの保持期間を超えると、メッセージがログから削除されるため、コンシューマーはメッセージを永久に失う可能性があります。
- コンシューマーグループのリバランス:永続的なラグは、不安定なコンシューマーグループの動作や頻繁なリバランスの原因となる可能性があります。
高いラグの一般的な原因:
- 遅いコンシューマーロジック:コンシューマーアプリケーション自体が各メッセージの処理に時間がかかりすぎています。
- 不十分なコンシューマーインスタンス:すべてのパーティションにわたるメッセージ量を処理するのに十分なコンシューマーインスタンスが実行されていません。
- ネットワークレイテンシ:コンシューマーとブローカー間の問題。
- ブローカーのパフォーマンス問題:ブローカーがメッセージを効率的に提供するのに苦労している可能性があります。
- メッセージ生成のスパイク:コンシューマーを圧倒する一時的なメッセージのバースト。
- 設定ミス:コンシューマーまたはトピックの設定が正しくありません。
kafka-consumer-groups.shを使用したラグの診断(推奨)
kafka-consumer-groups.shツールは、コンシューマーグループを管理および検査するための現代的で推奨される方法です。Kafkaブローカーと直接対話してコンシューマーオフセット情報を取得します。この情報は内部の__consumer_offsetsトピックに保存されます。このツールは、ラグを含むコンシューマーグループの状態に関する包括的な詳細を提供します。
コンシューマーグループを記述する基本的な使用法
特定のコンシューマーグループのラグを確認するには、--describeオプションと--groupオプションを使用します。
kafka-consumer-groups.sh --bootstrap-server <Kafka_Broker_Host:Port> --describe --group <Consumer_Group_Name>
<Kafka_Broker_Host:Port>をKafkaブローカーのアドレス(例:localhost:9092)に、<Consumer_Group_Name>を検査するコンシューマーグループの名前に置き換えます。
出力の解釈
典型的な出力は次のようになります。
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
my-consumer-app my-topic 0 12345 12347 2 consumer-1-a1b2c3d4-e5f6-7890-1234-abcdedfg /192.168.1.100 consumer-1
my-consumer-app my-topic 1 20000 20500 500 consumer-2-hijk-lmno-pqrs-tuvw-xyz /192.168.1.101 consumer-2
my-consumer-app my-topic 2 5000 5000 0 consumer-3-1234-5678-90ab-cdef-12345678 /192.168.1.102 consumer-3
my-consumer-app another-topic 0 900 900 0 consumer-1-a1b2c3d4-e5f6-7890-1234-abcdedfg /192.168.1.100 consumer-1
重要な列を分解してみましょう。
GROUP:コンシューマーグループの名前。TOPIC:消費されているトピック。PARTITION:トピックの特定のパーティション。CURRENT-OFFSET:このパーティションに対してコンシューマーが最後にコミットしたオフセット。LOG-END-OFFSET:このパーティションの最新メッセージのオフセット。LAG:LOG-END-OFFSETとCURRENT-OFFSETの差。これはコンシューマーが遅れているメッセージの数です。CONSUMER-ID:コンシューマーインスタンスの一意の識別子。これが-の場合、そのパーティションにアクティブなコンシューマーが割り当てられていないことを意味します。HOST:コンシューマーインスタンスのIPアドレスまたはホスト名。CLIENT-ID:コンシューマーインスタンスに設定されたクライアントID。
重要な観察点:
- 高い
LAG値:コンシューマーが遅れていることを示します。コンシューマーロジック、リソース、またはスケーリングを調査してください。 CONSUMER-IDが-:パーティションが消費されていないことを示唆します。これは、グループ内のアクティブなコンシューマーインスタンスの数が不十分であるか、コンシューマーインスタンスがクラッシュして再参加していないことが原因である可能性があります。そのようなパーティションでLAGが高い場合、重大な問題です。LAGが0:コンシューマーが最新のメッセージに完全に追いついていることを意味します。
consumer-offset-checker.shを使用したラグの診断(レガシーツール)
consumer-offset-checker.shは、コンシューマーオフセットの保存と取得にZooKeeperに依存していた古い非推奨のツールです(古いkafka.consumer.ZookeeperConsumerConnectorを使用するコンシューマーの場合)。最新のKafkaクライアント(0.9.0以降)では、オフセットはKafka自体に保存されます。kafka-consumer-groups.shに大部分が取って代わられていますが、古い環境やレガシーコンシューマークライアントで遭遇する可能性があります。
警告:非推奨のお知らせ
このツールはオフセット管理にZooKeeperに依存しています。最新のKafkaクライアント(0.9.0+)はオフセットをKafkaに直接保存します。新しいクラスターとクライアントでは、
kafka-consumer-groups.shが信頼できる推奨ツールです。コンシューマークライアントがオフセットをZooKeeperに保存するように設定されていることが明確にわかっている場合にのみ、consumer-offset-checker.shを使用してください。
基本的な使用法
このツールでラグを確認するには、ZooKeeper接続文字列を指定する必要があります。
consumer-offset-checker.sh --zk <ZooKeeper_Host:Port> --group <Consumer_Group_Name>
<ZooKeeper_Host:Port>(例:localhost:2181)と<Consumer_Group_Name>を置き換えます。
出力の解釈
Group Topic Partition Offset LogSize Lag Owner
my-old-app my-old-topic 0 1000 1050 50 consumer-1_hostname-1234-5678-90ab-cdef
my-old-app my-old-topic 1 2000 2000 0 consumer-2_hostname-abcd-efgh-ijkl-mnop
Group、Topic、Partition:kafka-consumer-groups.shと同様。Offset:コンシューマーによってコミットされたオフセット。LogSize:パーティションのLOG-END-OFFSET。Lag:コンシューマーが遅れているメッセージの数。Owner:現在パーティションを所有(消費)しているコンシューマーインスタンス。
ラグ値の解釈は同様です。高いラグは問題を示し、高いラグのパーティションにOwnerがないことは重大な問題です。
高いコンシューマーラグへの対処:戦略とオフセットリセット
高いコンシューマーラグを特定したら、次のステップはそれに対処することです。これには多くの場合、2つのアプローチがあります。まず根本原因を調査して修正し、次に必要に応じてコンシューマーオフセットをリセットします。
根本原因の調査
オフセットリセットに飛びつく前に、ラグが発生している理由を理解することが重要です。以下を確認してください。
- コンシューマーアプリケーションログ:エラー、過度の処理時間、またはアプリケーション障害の兆候を探します。
- コンシューマーホストメトリクス:CPU、メモリ、ネットワーク使用率を監視します。コンシューマーはリソースに制約されていますか?
- Kafkaブローカーメトリクス:ブローカーはストレス下にありますか?ディスクI/O、ネットワーク、CPUは高いですか?
- プロデューサースループット:メッセージ生成に予期しないスパイクはありましたか?
- コンシューマーグループの状態:頻繁なリバランスはありますか?
max.poll.interval.msに達していませんか?
コンシューマーのスケーリング
既存のコンシューマーがメッセージを十分な速さで処理できず、トピックに十分なパーティションがある場合、コンシューマーインスタンスを追加してコンシューマーグループをスケールアップする必要があるかもしれません。グループ内の各コンシューマーインスタンスは、すべてのパーティションが割り当てられるまで(最大パーティション数まで)、1つ以上のパーティションを引き継ぎます。
コンシューマーオフセットのリセット
コンシューマーオフセットをリセットするとは、コンシューマーグループがメッセージを読み取る開始点を変更することを意味します。これは強力で、潜在的に破壊的な操作であり、注意して使用する必要があります。
オフセットリセット前の重要な考慮事項:
- データ損失:
--to-latestにリセットすると、コンシューマーは現在のオフセットとログエンドオフセットの間のすべてのメッセージをスキップし、それらのメッセージが永久に失われます。- データ再処理:
--to-earliestまたは古いオフセットにリセットすると、コンシューマーはすでに処理したメッセージを再処理します。コンシューマーアプリケーションは、これを適切に処理するためにべき等(メッセージを複数回処理しても同じ結果になる)である必要があります。- アプリケーションの状態:再処理がコンシューマーアプリケーションやダウンストリームシステムによって管理される状態にどのように影響するかを検討してください。
オフセットをリセットするには、再びkafka-consumer-groups.shを使用します。オフセットのリセット方法にはさまざまなオプションがあります。
--to-earliest:パーティションで利用可能な最も古いオフセットにリセットします。--to-latest:パーティションの最新オフセットにリセットします(実質的に現在のすべてのメッセージをスキップします)。--to-offset <offset>:特定の希望するオフセットにリセットします。--to-datetime <YYYY-MM-DDTHH:mm:SS.sss>:特定のタイムスタンプに対応するオフセットにリセットします。--shift-by <N>:現在のオフセットをN位置シフトします(例:-10で10メッセージ戻る、+10で10メッセージ進む)。
重要な安全機能:--dry-runと--execute
--executeでコミットする前に、常に最初に--dry-runを実行して、リセット操作が何をするかを確認してください。
オフセットリセットのステップバイステッププロセス:
ターゲットコンシューマーグループのすべてのコンシューマーを停止します。これは、オフセットをリセットしようとしている間にコンシューマーが新しいオフセットをコミットするのを防ぐために重要です。
ドライランを実行して、オフセット変更をプレビューします。
例:最も古いオフセットにリセット(すべてのメッセージを再処理)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-earliest --topic my-topic --dry-run例:最新のオフセットにリセット(すべてのラグのあるメッセージをスキップ)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-latest --topic my-topic --dry-run例:特定のタイムスタンプにリセット(例:2023-01-01 00:00:00 UTCから開始)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-datetime 2023-01-01T00:00:00.000 --topic my-topic --dry-run例:オフセットを500メッセージ戻す(パーティションごと)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --shift-by -500 --topic my-topic --dry-run
--dry-runの出力は、提案されたオフセット変更を示します。GROUP TOPIC PARTITION NEW-OFFSET my-consumer-app my-topic 0 0 my-consumer-app my-topic 1 0ドライランの結果に満足したら、リセットを実行します。
- 例:最も古いオフセットにリセット(実行)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group my-consumer-app --reset-offsets --to-earliest --topic my-topic --execute
- 例:最も古いオフセットにリセット(実行)
コンシューマーアプリケーションを再起動します。オフセットがリセットされたら、コンシューマーインスタンスを再起動します。新しい開始オフセットからの消費を開始します。
ヒント:グループ内のすべてのトピックのリセット
グループによって消費されるすべてのトピックのオフセットをリセットする場合は、
kafka-consumer-groups.sh --reset-offsetsを使用する際に--topicフラグを省略できます。これはすべてに影響するため、特に注意してください。
コンシューマー運用のベストプラクティス
- プロアクティブな監視:Prometheus/Grafana、Datadog、またはカスタムスクリプトなどのツールを使用して、コンシューマーラグの堅牢な監視を実装します。急速に増加するラグや一貫して高いラグに対してアラートを設定します。
- べき等性を理解する:コンシューマーアプリケーションをべき等になるように設計します。これにより、障害やオフセットリセットが発生した場合でも、メッセージを安全に再処理できます。
max.poll.interval.msを調整する:この設定は、コンシューマーがポーリングなしでいられる最大時間を定義します。処理ロジックが遅い場合は、この値を増やして不要なリバランスを防ぎますが、根本的な遅さも調査してください。- 処理できないメッセージを処理する:繰り返し失敗してコンシューマーをブロックするのではなく、「ポイズンピル」メッセージ(例:デッドレターキュー(DLQ)に送信する)の戦略を実装します。
- グレースフルシャットダウン:コンシューマーアプリケーションがグレースフルにシャットダウンし、最終オフセットをコミットして、再起動時の不要な再処理やラグのスパイクを回避するようにします。
- パーティションとコンシューマーを一致させる:最適な並列処理のために、実行する予定のコンシューマーインスタンスと少なくとも同数のパーティションを目指します。パーティションが多いほど、より多くの並列処理が可能になります。
実践的なインシデントフロー
ラグがアラートを発したときは、最初にオフセットをリセットしたい衝動を抑えてください。まず現在のグループ状態をキャプチャします。
kafka-consumer-groups.sh --bootstrap-server kafka-1:9092 --describe --group payments-writer
サイズだけでなく、形状を確認してください。すべてのパーティションがほぼ同じ量だけラグっている場合、グループ全体がおそらくプロビジョニング不足か、共有依存関係でブロックされています。1つのパーティションが大幅に遅れている場合は、キーの偏り、ポイズンメッセージ、またはCPU、ディスク、DNS、ネットワーク動作が悪い単一のコンシューマーホストを確認してください。CONSUMER-IDが-の場合、そのパーティションには現在アクティブなメンバーが割り当てられていません。これは通常、クラッシュしたコンシューマー、進行中のリバランス、または予想よりも少ない正常なメンバーを持つグループを指します。
1分後にコマンドを再度実行します。ラグ値が500,000でも、デプロイロールバック後に急速に減少している場合はそれほど心配する必要はありません。ラグ値が5,000でも、通常のトラフィック中に毎分倍増する場合はより心配です。インシデント中は、通常、合計ラグ、最悪のパーティションラグ、グループ状態が安定しているかどうかの3つの数値を書き留めます。これにより、コンシューマーをスケーリングするか、プロデューサーを遅くするか、アプリケーションエラーを修正するか、制御されたリプレイを準備するかを決定するのに十分なシグナルが得られます。
リセットする前に、現在のオフセットを耐久性のある場所に保存してください。たとえそれがインシデントチケットだけでも構いません。ドライランはバックアップではありません。コマンド出力は、リセットによってまだ重要だったデータがスキップされたことに誰かが気付いた場合に必要になる可能性のあるオフセットを提供します。
最終確認
健全なラグのランブックには3つの習慣があります。変更する前に記述し、実行する前にドライランし、オフセットを移動する前にコンシューマーを修正する。kafka-consumer-groups.shは、コミットされたオフセットとパーティションの所有権に関する生の真実を提供します。あなたの仕事は、その出力を背後にあるアプリケーションの動作に結び付けることです。