Kafkaブローカ障害のトラブルシューティングと復旧戦略

この包括的なガイドでは、ハードウェアの問題から設定ミスまで、Kafkaブローカ障害の一般的な原因を探ります。ログ分析、リソース監視、JVM診断を含む体系的なトラブルシューティング手順を学び、根本原因を迅速に特定します。ブローカの再起動、データ破損の処理、キャパシティ計画などの効果的な復旧戦略を発見します。また、より回復力のあるKafkaクラスタを構築し、ダウンタイムを最小限に抑え、分散イベントストリーミングプラットフォームでのデータ整合性を確保するための重要な予防策とベストプラクティスを強調します。

Kafkaブローカ障害のトラブルシューティングと復旧戦略

Kafkaブローカが障害を起こすと、最初に気づくのは通常、別の場所での症状です。コンシューマが遅れ、プロデューサがタイムアウトし、ダッシュボードにアンダーレプリケーションパーティションが表示され、イベントが届かないためにデプロイメントパイプラインがブロックされます。ブローカ自体は、プロセスが消えた、起動でスタックした、または動作しているが遅すぎて役に立たないという、単純な事実だけを示すかもしれません。

Kafkaブローカ障害のトラブルシューティングに役立つ方法は、3つの質問を迅速に分離することです。ブローカプロセスはクラッシュしましたか?ノードまたはディスクがブローカを異常にしましたか?それとも、ブローカは実行中ですが、クラスタに正しく参加できませんか?これらのパスは異なる修正につながり、それらを混同すると、小さな障害が長時間の障害に変わります。

Kafkaブローカ障害の理解

Kafkaブローカは、ハードウェアの問題からソフトウェアの設定ミスまで、さまざまな理由で障害を起こす可能性があります。根本原因を特定することが、効果的な復旧への第一歩です。以下は、最も一般的な原因の一部です。

1. ハードウェアとインフラストラクチャの問題

  • ディスク障害: ログにIOExceptionLogSegmentCorruptedExceptionが頻繁に発生します。ブローカはメッセージの永続ストレージのためにディスクI/Oに大きく依存しています。
  • メモリ不足(OOM): RAMが不十分だと、JVMがクラッシュしたり、オペレーティングシステムがKafkaプロセスを強制終了したりする可能性があります。症状には、ログのOutOfMemoryErrorやシステムレベルのOOMキラーメッセージが含まれます。
  • CPU過負荷: CPU使用率が高いと、ブローカが大幅に遅くなり、タイムアウトや応答不能を引き起こす可能性があります。
  • 停電: 制御されていないシャットダウンは、特にfsync設定が最適でない場合、ログセグメントやZookeeperデータを破損させる可能性があります。

2. ネットワークの問題

  • 接続の問題: ブローカは、他のブローカ、Zookeeper、またはクライアントへの接続を失う可能性があります。これは、NetworkExceptionSocketTimeoutException、またはZookeeperセッションの期限切れとして現れることがあります。
  • 高レイテンシ/パケット損失: ネットワークパフォーマンスの低下は、レプリケーションラグ、コンシューマグループのリバランス、ブローカ選出の失敗を引き起こす可能性があります。

3. JVMとOSの設定

  • 誤ったJVMヒープ設定: ヒープが小さすぎるとOutOfMemoryErrorが発生します。大きすぎると、過剰なガベージコレクション(GC)ポーズにより、ブローカが応答不能に見える可能性があります。
  • ファイル記述子制限: Kafkaは多くのファイル(ログセグメント、ネットワーク接続)を開きます。ファイル記述子のOSのulimitを超えると、Too many open filesエラーが発生する可能性があります。
  • スワッピング: OSがメモリをディスクにスワップし始めると、パフォーマンスが大幅に低下します。Kafkaノードでは、理想的にはスワッピングを無効にする必要があります。

4. ディスクI/Oとストレージ

  • 不十分なディスクスループット: ディスクが書き込み要求に追いつけない場合、I/O待機が高くなり、メッセージが蓄積され、最終的にブローカが応答不能になる可能性があります。
  • ディスク満杯: ディスクがいっぱいになると、Kafkaは新しいメッセージを書き込めなくなり、IOException: No space left on deviceが発生し、ブローカが停止します。
  • ログ破損: まれに、特に不適切なシャットダウン後、ログセグメントが破損し、ブローカの起動やデータ提供が妨げられることがあります。

5. メタデータクォーラムまたはZookeeperの問題

  • Zookeeperの利用不可: まだZookeeperを使用しているKafkaクラスタは、コントローラ選出やトピックメタデータを含むメタデータ管理をZookeeperに依存しています。Zookeeperがダウンしているか遅い場合、ブローカはセッションの期限切れ、コントローラの変動、またはメタデータ同期の問題を示す可能性があります。
  • KRaftコントローラの問題: 新しいKafkaデプロイメントでは、Zookeeperの代わりにKRaftモードを使用する場合があります。これらのクラスタでは、コントローラクォーラムの健全性が重要です。コントローラ選出の不安定性、クォーラム接続の問題、メタデータログレプリケーションに言及しているブローカログを探します。

6. ソフトウェアのバグと設定エラー

  • Kafkaソフトウェアのバグ: 安定版リリースではあまり一般的ではありませんが、特に新しいバージョンや特定のエッジケースでは可能性があります。
  • 設定ミス: 誤ったserver.properties設定(例:listenersadvertised.listenerslog.dirsreplication.factorの影響)により、ブローカがクラスタに参加したり、正しく動作したりできなくなる可能性があります。

体系的なトラブルシューティング手順

Kafkaブローカが障害を起こした場合、問題を迅速に特定して解決するには体系的なアプローチが鍵となります。

1. 初期評価:基本ステータスの確認

  • Kafkaプロセスが実行中かどうかを確認します。
    systemctl status kafka # systemdサービスの場合
    # または
    ps aux | grep -i kafka | grep -v grep
    
  • 他のブローカ/クライアントからのブローカ接続を確認します。
    netstat -tulnp | grep <kafka_port>
    # または、別のマシンからポートをテストするためにncを使用します
    nc -zv <broker_ip> <kafka_port>
    

2. システムリソースの監視

tophtopfree -hiostatdf -hvmstatなどのツールを使用して、以下を確認します。

  • CPU使用率: 一貫して高いですか?I/O待機サイクルは多いですか?
  • メモリ使用率: システムはOOMに近いですか?過剰なスワッピングはありますか?
  • ディスクI/O: 書き込み/読み取りレイテンシまたはスループットの飽和が高いですか?iostat -x 1を使用してディスクのボトルネックを特定します。
  • ディスク容量: log.dirsパーティションはいっぱいですか?df -h <kafka_log_directory>
  • ネットワークアクティビティ: トラフィックに異常なスパイクや低下はありますか?エラー率は高いですか?

3. Kafkaブローカログの分析

Kafkaログ(デフォルトではkafka-logs/server.log)は、最も重要な診断ツールです。以下を探します。

  • エラーメッセージ: 障害の直前に発生したERRORWARNレベルのメッセージ。
  • 例外: OutOfMemoryErrorIOExceptionSocketTimeoutExceptionLogSegmentCorruptedException
  • GCアクティビティ: 長いGCポーズ(有効になっている場合、GCログからのINFOメッセージで示されます)。
  • Zookeeper接続の問題: セッションの期限切れや再確立に関するINFOメッセージ。
  • コントローラ選出: Kafkaコントローラとその選出プロセスに関連するメッセージ。

ヒント: 本番環境では、ログ保持期間を延ばし、GCログを有効にして、事後分析を改善します。

4. JVM診断

メモリまたはCPUが問題であると思われる場合は、JVM固有のツールを使用します。

  • jstat -gc <pid> 1000: ガベージコレクションの統計を監視します。高いFGC(Full GC)カウントまたは長いFGCT(Full GC Time)を探します。
  • jstack <pid>: スレッドダンプを取得して、JVMが何をしているかを確認します。デッドロックや長時間実行操作の特定に役立ちます。
  • jmap -heap <pid>: ヒープメモリ使用量を表示します。
  • jcmd <pid> GC.heap_dump <file>: Eclipse MATなどのツールで詳細なメモリ分析を行うためのヒープダンプを作成します。

5. メタデータレイヤのヘルスチェック

クラスタが実際に使用しているメタデータシステムを確認します。

Zookeeperベースのクラスタの場合:

  • Zookeeperサービスのステータスを確認します。
    systemctl status zookeeper
    
  • Zookeeperログファイルを確認します: Kafkaからの接続の問題、Zookeeperアンサンブル内の選出問題を探します。
  • zkCli.shを使用してZookeeperに接続し、Kafka関連のznodeをリストします: ls /brokers/idsls /controller

KRaftベースのクラスタの場合、コントローラとブローカのログを一緒に検査します。ブローカがOSレベルでは正常でも、メタデータを登録またはフェッチできない場合、次に確認するのはコントローラクォーラムです。

6. 設定のレビュー

障害が発生したブローカのserver.propertiesを、正常に動作しているブローカと比較します。特にlog.dirslistenersadvertised.listenersbroker.idzookeeper.connectの微妙な違いや最近の変更を探します。

効果的な復旧戦略

問題を特定したら、適切な復旧戦略を実装します。

1. 再起動が実際に安全かどうかを判断する

再起動は、必要な証拠(最近のブローカログ、システムログ、ディスクステータス、アンダーレプリケーションまたはオフラインのパーティションのリスト)を収集した後に行うのが妥当です。早すぎる再起動は、有用なプロセス状態を消去し、繰り返し発生するクラッシュを5つの無関係なインシデントのように見せかける可能性があります。

# Kafkaを停止
systemctl stop kafka
# 正常なシャットダウンメッセージのログを確認
# Kafkaを起動
systemctl start kafka
# 起動の問題のログを監視

ブローカが繰り返しクラッシュしている場合は、再起動を修正として扱うのをやめてください。その時点では、それはテストにすぎません。起動ログを最初の行から監視してください。Kafkaは通常、ログリカバリ、リスナーバインディング、ストレージアクセス、メタデータ登録、またはJVM起動のどこでスタックしているかを教えてくれるからです。

2. 故障したハードウェア/VMの交換

永続的なハードウェア障害(ディスク、メモリ、CPU)の場合、解決策は故障したマシンまたはVMを交換することです。新しいインスタンスが同じホスト名/IP(静的の場合)、マウントポイント、Kafka設定を持っていることを確認します。データディレクトリが失われた場合、replication.factor > 1を前提として、Kafkaはクラスタに再参加すると他のブローカからデータを複製します。

交換品を戻す前に、デプロイメントのブローカIDルールを確認してください。間違ったログディレクトリでブローカIDを再利用すると、混乱を引き起こす可能性があります。クラスタがまだ古いIDを期待しているときに、新しいIDでブローカを起動すると、存在しなくなったブローカにレプリカが割り当てられたままになる可能性もあります。計画的な交換では、クラスタがあいまいな状態を整理するのに頼るのではなく、レプリカの割り当てを意図的に更新します。

3. データリカバリとログ破損

ログセグメントが破損している場合(例:LogSegmentCorruptedException)、ブローカが起動に失敗する可能性があります。

  • オプションA: 破損したログを削除する(レプリケーションファクタが許可する場合): 影響を受けるトピックのreplication.factorが1より大きく、正常なレプリカが存在する場合、障害が発生したブローカ上の問題のあるパーティションの破損したログディレクトリを削除できます。Kafkaはその後、データを再複製します。

    1. Kafkaブローカを停止します。
    2. ログから破損したlog.dirsエントリを特定します。
    3. 問題を引き起こしているlog.dirs内のパーティションディレクトリを手動で削除します(例:rm -rf /kafka-logs/topic-0)。
    4. ブローカを再起動します。
  • オプションB: kafka-log-dirs.shツールを使用する: このツールは、レプリカの再割り当てやログディレクトリの移動に使用できます。ログ破損の場合、より積極的なアプローチが必要になる場合があります。Kafkaのバージョンには、特定のリカバリシナリオのための内部ツールが含まれていることがよくありますが、他の場所にレプリカが存在する場合、真に破損したセグメントには手動削除が一般的です。

4. パーティションの複製(失われた場合)

ブローカが障害を起こし、そのデータが完全に失われた場合(例:replication.factor=1でのディスククラッシュ、またはレプリケーションファクタを超える複数の障害)、一部のデータは復元できない可能性があります。ただし、replication.factor > 1の場合、Kafkaは自動的に新しいリーダーを選出し、データを復旧します。障害が発生したブローカが完全に使用不能になった場合は、kafka-reassign-partitions.shを使用してリーダーシップのバランスを再調整したり、パーティションを正常なブローカに再割り当てしたりする必要があるかもしれません。

5. 設定の更新

障害が設定ミスによるものである場合は、server.propertiesを修正し、ブローカを再起動します。JVM関連の問題(例:OutOfMemoryError)の場合は、kafka-server-start.shまたはkafka-run-class.shKAFKA_HEAP_OPTSを調整し、再起動します。

# 例:ヒープサイズを増やす
export KAFKA_HEAP_OPTS="-Xmx8G -Xms8G"
# その後、Kafkaを起動

6. キャパシティ計画とスケーリング

一貫したリソースの枯渇(CPU、メモリ、ディスクI/O、ネットワーク)は、スケーリングの必要性を示しています。これには以下が含まれる場合があります。

  • クラスタへのブローカの追加。
  • 既存のブローカハードウェアのアップグレード。
  • トピック設定の最適化(例:num.partitionssegment.bytes)。
  • コンシューマ効率の改善。

実用的なトリアージフロー

プレッシャーがかかっているときは、知っているすべてのKafkaコマンドから始めないでください。障害がどこにあるかを示す最小限のセットから始めてください。

まず、ブローカプロセスが生きていてリッスンしているかどうかを確認します。

systemctl status kafka
ss -lntp | grep 9092
jps -l | grep kafka

プロセスがダウンしている場合、ブローカログとシステムジャーナルが主要な証拠です。最後のエラーではなく、最初の重大なエラーを探してください。最後の行は単にサーバーがシャットダウンしたことを示しているだけかもしれません。有用な行は、Kafkaがログディレクトリを開けなかったり、リスナーをバインドできなかったり、ヒープを割り当てられなかったり、メタデータレイヤに接続できなかったりした、数百行前にあることがよくあります。

プロセスが生きている場合は、クラスタがまだそれを有用と見なしているかどうかを尋ねます。

kafka-broker-api-versions.sh --bootstrap-server <broker-host>:9092
kafka-topics.sh --bootstrap-server <bootstrap-host>:9092 --describe --under-replicated-partitions

ブローカは、オペレーティングシステムの観点からは生きていても、クラスタの観点からは悪いブローカである可能性があります。たとえば、TCP接続を受け入れても、低速なディスクから読み取れないためにリクエストが失敗する可能性があります。または、ラップトップからは到達可能でも、advertised.listenersが間違ったアドレスを指しているため、他のブローカからは到達できない可能性があります。

次に、ノードを確認します。

df -h
iostat -x 1
free -h
dmesg -T | tail -100

最も一般的な実際のパターンは、神秘的なKafkaのバグではありません。それは、ディスク満杯、ディスク障害、同じホスト上のノイジーネイバー、メモリプレッシャー下のJVM、または設定変更中に導入されたリスナー/ネットワークの不一致です。

エラーが通常意味すること

No space left on deviceは直接的です。再起動する前に、空き容量を増やすかストレージを追加してください。また、保持設定が期待通りに機能しているかどうかを確認してください。予期せず長い保持期間を持つトピックや、クリーナーの進行が遅いコンパクトトピックは、静かにディスクを満たす可能性があります。

Too many open filesは、Kafkaプロセスのオペレーティングシステム制限を指します。Kafkaはログセグメントファイルとネットワークソケットを開くため、低いデフォルト値は危険です。サービスユーザーのファイル記述子制限を引き上げ、シェルセッションだけでなく、実行中のプロセスからも確認してください。

OutOfMemoryErrorは、JVMがメモリを割り当てられなかったことを意味しますが、原因は常に「ヒープが小さすぎる」とは限りません。リーク、ブローカ上のパーティションが多すぎる、非常に大きなリクエスト処理、またはファイルシステムページキャッシュに残すメモリが少なすぎるヒープサイズの誤りである可能性があります。KafkaはOSのページキャッシュに大きく依存しているため、すべてのRAMをJVMに与えると、ディスクの動作が悪化する可能性があります。

Connection to node -1 could not be establishedは、クライアントのブートストラップ中によく表示され、advertised.listenersが原因である可能性があります。クライアントがブートストラップアドレスに接続できても、解決できない内部ホスト名を受け取った場合、最初のメタデータ応答の後に失敗します。

ブローカ障害後のLeader not availableは、通常、リーダーシップがまだ移行中であるか、影響を受けるパーティションに準備の整った同期レプリカがないことを意味します。トピックに十分なレプリケーションがあるかどうか、およびmin.insync.replicasが現在正常なレプリカの数と互換性があるかどうかを確認してください。

予防策とベストプラクティス

プロアクティブな対策により、ブローカ障害の可能性と影響を大幅に削減できます。

  • 堅牢な監視とアラート: システムリソース(CPU、メモリ、ディスクI/O、ネットワーク)、JVMメトリクス(GC、ヒープ使用量)、Kafka固有のメトリクス(アンダーレプリケーションパーティション、コントローラステータス、コンシューマラグ)の包括的な監視を実装します。重要なしきい値に対してアラートを設定します。
  • 適切なリソース割り当て: 十分なCPU、メモリ、高性能ディスク(SSDを強く推奨)を備えたブローカをプロビジョニングします。仮想化環境でのオーバーサブスクリプションを避けます。
  • 定期的なメンテナンスとアップデート: Kafkaとその依存関係(JVM、OS)を最新の状態に保ち、バグ修正とパフォーマンス改善の恩恵を受けます。非本番環境でアップデートを徹底的にテストします。
  • 高可用性設定: データの冗長性とフォールトトレランスを確保するために、本番トピックでは常に1より大きいreplication.factor(通常は3)を使用します。これにより、データ損失やサービス中断なしにブローカが障害を起こすことができます。
  • ディザスタリカバリ計画: 重要な設定と場合によってはログセグメントの定期的なバックアップを含む、データリカバリの明確な計画を立てます(ただし、Kafkaのレプリケーションがデータの主要なDRメカニズムです)。
  • スワッピングを無効にする: Kafkaブローカマシンでvm.swappiness=0またはswapoff -aを確認します。
  • ファイル記述子制限を増やす: Kafkaユーザーに高いulimit -n(例:128000以上)を設定します。

ブローカ復旧後

ブローカが起動した瞬間にインシデントをクローズしないでください。レプリカが追いついたか、パーティションがオフラインのままか、コンシューマが正常に復旧しているかを確認してください。

kafka-topics.sh --bootstrap-server <bootstrap-host>:9092 --describe --under-replicated-partitions
kafka-consumer-groups.sh --bootstrap-server <bootstrap-host>:9092 --all-groups --describe

また、正確な最初の障害信号を書き留めてください。「ブローカがダウンした」は根本原因ではありません。「ログディレクトリ/data2/kafkaがI/Oエラーを返した後にブローカが停止した」は、次のメンテナンスウィンドウで防止、監視、テストできるものです。