Kafkaを監視する3つのアプローチ — それぞれに向き不向きがある理由
まともなモニタリングを導入する前は、lagを確認するために各brokerにSSHして kafka-consumer-groups.sh を実行していた — 非常に時間がかかるうえ、問題を早期に検知できなかった。今はダッシュボードを開くだけで、throughputからconsumer groupごとのlagまで、クラスター全体の状況が一目でわかる。
しかしその状態に至るまでに、3つの主要なアプローチを試し、それぞれに固有の弱点があることを学んだ。
アプローチ1:AKHQ(Kafka HQ)— 純粋なGUI
AKHQはtopic・consumer group・broker statusを確認できるWeb UIだ。セットアップが簡単で直感的に使え、クラスターを把握するのに適している。しかし大きな弱点がある:time-seriesがなく、アラートもなく、共通のアラートシステムへの統合もできない。深夜3時に障害が起きたとき、誰もAKHQを手動で確認しに行くわけにはいかない。
アプローチ2:Burrow(LinkedIn製)
Burrowはconsumer lagの追跡に特化したツールで、「consumer health」を評価するアルゴリズムが優れている — 瞬間的なlagを見るだけでなく、トレンド分析も行う。しかしセットアップが複雑で、metricsをPrometheusに送るためのadapterが別途必要であり、2022年頃からコミュニティの活動が低下している。
アプローチ3:JMX Exporter + kafka-exporter + Prometheusの組み合わせ
これが現在本番環境で使っているスタックだ。2つのexporterは互いを補完する:JMX ExporterはKafka JMXから詳細なmetricsを取得し(broker-level:throughput・request rate・replication lag)、kafka-exporterはconsumer groupとtopicのmetricsを取得する(lag・offset・partition count)。どちらもPrometheus互換のエンドポイントをexposeする。
正しい選択のためのメリット・デメリット分析
3つすべてを試した結果、実際の比較は次のとおりだ:
- AKHQ:セットアップが速く、UIも優れている — しかしアラートなし、time-seriesなし、共通のobservabilityスタックへの統合不可。
- Burrow:consumer healthの評価がより高度 — しかし導入が複雑で、専用のadapterが必要で、メンテナンスが少ない。
- JMX Exporter + kafka-exporter:metricsが充実し、Prometheus/Grafana/Alertmanagerに統合できる — ただし初期設定に多くのステップが必要。
3番目のスタックを選んだ理由:インフラ全体でPrometheusがすでに稼働していたからだ。GrafanaダッシュボードでKafka metricsをサーバーmetrics(CPU・memory・disk I/O)と相関させることができる — ボトルネックがKafkaにあるのかconsumer serviceにあるのかわからないパフォーマンス問題のデバッグに非常に役立つ。
状況に応じた適切なスタックの選び方
- 小規模チーム・少数のbroker・素早いvisibilityが必要な場合:AKHQで十分に始められる。
- consumer lagの専門的な監視が必要で、複雑なアラートは不要な場合:Burrow + Burrow-exporter。
- 本番環境・アラートが必要・既存のobservabilityスタックへの統合が必要な場合:JMX Exporter + kafka-exporter + Prometheus + Grafana。
デプロイガイド:JMX Exporter + kafka-exporter
ステップ1:Kafka BrokerにJMX Exporterを設定する
JMX ExporterはKafkaプロセスにアタッチするJava agentとして動作する。agent jarをダウンロードする:
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.20.0/jmx_prometheus_javaagent-0.20.0.jar \
-O /opt/kafka/libs/jmx_prometheus_javaagent.jar
最も重要なmetricsを含む設定ファイル /opt/kafka/config/kafka-jmx-exporter.yaml を作成する:
startDelaySeconds: 0
ssl: false
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
- pattern: 'kafka.server<type=BrokerTopicMetrics, name=MessagesInPerSec><>OneMinuteRate'
name: kafka_broker_messages_in_per_sec
- pattern: 'kafka.server<type=BrokerTopicMetrics, name=BytesInPerSec><>OneMinuteRate'
name: kafka_broker_bytes_in_per_sec
- pattern: 'kafka.server<type=BrokerTopicMetrics, name=BytesOutPerSec><>OneMinuteRate'
name: kafka_broker_bytes_out_per_sec
- pattern: 'kafka.server<type=ReplicaManager, name=UnderReplicatedPartitions><>Value'
name: kafka_broker_under_replicated_partitions
- pattern: 'kafka.controller<type=KafkaController, name=ActiveControllerCount><>Value'
name: kafka_broker_active_controller_count
KafkaのスタートアップファイルにJVMフラグを追加する — 通常は KAFKA_OPTS 変数を使う:
export KAFKA_OPTS="-javaagent:/opt/kafka/libs/jmx_prometheus_javaagent.jar=7071:/opt/kafka/config/kafka-jmx-exporter.yaml"
brokerを再起動後、エンドポイントを確認する:
curl http://localhost:7071/metrics | grep kafka_broker
ステップ2:kafka-exporterをデプロイする
kafka-exporterはスタンドアロンのGoバイナリで、Kafkaクラスターに接続してconsumer groupとtopicのmetricsを取得する:
docker run -d --name kafka-exporter \
-p 9308:9308 \
danielqsj/kafka-exporter \
--kafka.server=kafka-broker-1:9092 \
--kafka.server=kafka-broker-2:9092 \
--kafka.server=kafka-broker-3:9092
consumer lagのmetricsが正しくexposeされているか確認する:
curl http://localhost:9308/metrics | grep kafka_consumergroup_lag
ステップ3:Prometheusのscrape設定を追加する
prometheus.yml に2つのjobを追加する:
scrape_configs:
- job_name: 'kafka-jmx'
static_configs:
- targets:
- 'kafka-broker-1:7071'
- 'kafka-broker-2:7071'
- 'kafka-broker-3:7071'
scrape_interval: 30s
- job_name: 'kafka-exporter'
static_configs:
- targets: ['kafka-exporter:9308']
scrape_interval: 15s
scrape intervalが異なる理由:JMX metricsの変化は緩やかなため30秒で十分だ。kafka-exporterはlag spikeをアラートのしきい値を超える前に早期検知するために15秒が必要だ。
ステップ4:GrafanaダッシュボードをImportする
Grafana.comで最も適した2つのダッシュボードがある:
- Dashboard ID 7589 — Kafka Overview(kafka-exporter metricsを使用、consumer lagに焦点を当てる)
- Dashboard ID 721 — Kafka Metrics(JMX metricsを使用、broker internalに焦点を当てる)
Importの手順:Grafana → Dashboards → Import → IDを入力 → Prometheusデータソースを選択。
最重要metricsとPromQLの書き方
Consumer Lag — 最優先でアラートを設定すべきmetric
Consumer lagとは、producerがpartitionに書き込んだがconsumerがまだ処理していないmessage数のことだ。lagが継続的に増加するということは、consumerがproducerに追いつけていないことを意味する — これがpipelineの障害を示す最初のサインだ。
# consumer groupごとのtopic別総lag
sum(kafka_consumergroup_lag{consumergroup="my-app-group"}) by (topic)
# lagがしきい値を超えた際のアラート(各groupのSLAに応じて設定)
alert: KafkaConsumerLagHigh
expr: kafka_consumergroup_lag{consumergroup="payment-consumer"} > 5000
for: 5m
Broker Throughput
# クラスター全体のMessages per second
sum(kafka_broker_messages_in_per_sec) by (instance)
# 帯域幅監視用のBytes in/out
sum(kafka_broker_bytes_in_per_sec) by (instance)
sum(kafka_broker_bytes_out_per_sec) by (instance)
Topic Health — Under-replicated Partitions
これは最も高いアラート優先度を設定しているmetricsだ。UnderReplicatedPartitions > 0 の場合、一部のreplicaがleaderへの同期に追いつけていないことを意味する — このタイミングでbrokerが落ちると、messageを失うリスクがある。
# under-replicated partitionが発生したら即座にアラート — for: delayは不要
alert: KafkaUnderReplicatedPartitions
expr: kafka_broker_under_replicated_partitions > 0
# Active controllerはクラスター全体で常に正確に1つでなければならない
alert: KafkaControllerAbnormal
expr: sum(kafka_broker_active_controller_count) != 1
本番環境からの実践的なヒント
- consumer lagのアラートをgroupごとに分ける:クラスター全体のlag合計でアラートするのは避けよう — 各consumer groupはthroughputとSLAが異なる。payment処理groupのしきい値は1,000が必要だが、analyticsグループは100,000まで許容できる場合がある。
- Grafana variableを追加する:ダッシュボードに
consumergroupとtopicのvariableを作成して、troubleshoot時にqueryを書き直さずに素早くフィルタリングできるようにする。 - Kafka ExporterとSASL:クラスターでauthenticationが有効な場合、kafka-exporter実行時に
--sasl.enabled --sasl.username --sasl.password --sasl.mechanismフラグを追加する。 - Network partitionのアラート:
kafka_controller_offline_partitions_countmetricsも監視する — partition offlineはbroker間のnetwork issueを示すことが多い。
このスタックをセットアップしてから、「consumer lagが急増」というアラートが来ると、チームは同じGrafanaダッシュボード上で即座に相関分析ができるようになった:consumer serviceのCPU/memory、brokerのnetwork throughput、disk I/O。5台の異なるサーバーにSSHで個別に接続するのではなく、すべての情報が1つの画面に集約されている — デバッグ時間が20分から3〜4分に短縮された。

