今日、Apache Kafka は IT の世界で最も広く使われているソフトウェアの一つです。あらゆるところにあり、イベントストリーミングの事実上の標準であり、大企業全般で広く採用されています。Apache Kafka プロジェクトによれば、Kafka は数千もの組織で使われ、Fortune 100 企業の 80% 以上に信頼されています。
多くの組織で、Kafka はシステムの基盤であり、Kafka のエコシステムは絶えず成長しています。
しかし、信頼性の高い Kafka クラスターを運用することは難しい場合があります。broker レベルと topic レベルの両方に多くの設定があり、分散システムであり、そして当然ながら私たちはそれを高可用にしたいと考えます。
監視は極めて重要です。メトリクスの収集、ダッシュボードの構築、そして最終的にはアラートの定義を適切にセットアップしなければ、運用チームは目隠し状態です。
この記事では、Kafka のメトリクスに関する既知の問題を説明し、その大部分を——うまくいけばすべてを——解決する解決策を提案します。
Grafana の Kafka ダッシュボードをインポートしたのに、データが何も表示されなかったことはありませんか?その答えは以下にあります。
そもそも Kafka とは何か?
この記事を読んでいるなら、Kafka が何で、その目的が何かを完璧に理解していることに賭けてもいいでしょう。しかし、念のため手短におさらいします。
Apache Kafka は分散イベントストリーミングプラットフォームです。最もシンプルな考え方はこうです。Kafka は耐久性のある追記専用ログであり、多くのアプリケーション——producer——がそこにイベントを書き込み、他の多くのアプリケーション——consumer——がそのイベントをリアルタイムに、非常に高いスループットで読み戻すことを可能にします。
イベントは topic に存在し、それは partition に分割され、Kafka クラスターを構成するサーバーである複数の broker にまたがってレプリケートされます。これにより水平スケーラビリティと耐障害性が得られます。broker が停止しても、別のレプリカが引き継ぎ、consumer は一拍も逃すことなく読み続けられます。
今日、Kafka は多くのミッションクリティカルなシステムの中心に位置しています。決済パイプライン、不正検知、マイクロサービス間通信、データベースからの変更データキャプチャ、ログ集約、IoT テレメトリーなどです。うまく動いているときは誰も気づきません。うまく動かないときは、それは災害です。
Kafka 内部のメトリクスシステム——問題の根源
Kafka の broker が二つの異なるメトリクスシステムを通じてメトリクスを公開していることをご存じでしたか?私は知りませんでした。
Kafka のメトリクスは、同じ JVM 上で動作する二つの別々のメトリクスライブラリによって扱われています。
古い方は Yammer Metrics です。Kafka の初期からあり、BytesInPerSec、MessagesInPerSec、UnderReplicatedPartitions など、多くの基本的な broker メトリクスは今もこれによって扱われています。
二つ目は Kafka Metrics、すなわち org.apache.kafka.common.metrics で、SPI——Service Provider Interface——とも呼ばれます。これは Java クライアントが作られたときに導入されました。Kafka Streams や Kafka Connect といったエコシステムツールでも使われています。
これは単なる雑学ではありません。公式の Apache Kafka 監視ドキュメントによれば、Kafka はサーバーメトリクスに Yammer Metrics を使い、Java クライアントは Kafka Metrics を使います。どちらも JMX を通じてメトリクスを公開し、プラグイン可能な統計レポーターで設定できます。
これら二つのシステムは歴史的な理由から存在します。ある段階で、すべての新しいメトリクスは SPI メトリクスとして作られるようになりましたが、Yammer メトリクスを SPI に移行する計画はありませんでした。
主な違いは次のとおりです。
| 領域 | Yammer Metrics MBean | Kafka Metrics MBean |
|---|---|---|
| Kafka での主な用途 | 従来の broker/サーバー/controller メトリクス | Java クライアントと新しい/共通の broker/controller モジュール |
| レポーター設定 | kafka.metrics.reporters | metric.reporters |
| レポーターインターフェース | kafka.metrics.KafkaMetricsReporter | org.apache.kafka.common.metrics.MetricsReporter |
| デフォルトの JMX 公開 | Yammer JMX レポーター | org.apache.kafka.common.metrics.JmxReporter |
| MBean の形 | メトリクス名は通常 ObjectName の一部で、name=... として表される | ObjectName は通常ドメイン + type + タグ。メトリクス名は通常は属性 |
| 属性 | Value、Count、MeanRate、OneMinuteRate、パーセンタイルといった汎用的な Yammer 属性 | byte-rate、throttle-time、connection-count、*-rate、*-total といった Kafka メトリクス名が属性 |
| 例のスタイル | kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec,topic=my-topic | kafka.server:type=Produce,user=alice,client-id=app1 に byte-rate、throttle-time などの属性 |
Kafka メトリクスのセットアップ——昔ながらのやり方
Kafka を監視する伝統的な方法は、Prometheus JMX Exporter を使って JMX からメトリクスをエクスポートすることです。これは Java エージェントとして動作するライブラリで、ルールファイルとポート番号で設定します。
ポートは Prometheus エンドポイントとして使われ、末尾に /metrics が付きます。
ではルールファイルとは?それは膨大な YAML ファイルで、おびただしい数の正規表現が詰まっています。たいてい、誰もその詳細を完全には理解しておらず、それを書いた人が何をしているか分かっていたことを願いながら、ただ使っているだけです。
つまり、JMX Exporter をすべての broker にアップロードし、場合によってはルールを含む設定ファイルを作成または編集し——うまくいくことを祈ります——broker を再起動しなければなりません。すべてが順調に進めば、メトリクスエンドポイントを curl してメトリクスを見ることができます。よし!
それから、これらのメトリクスを Prometheus にスクレイプし、Grafana でいくつかの Kafka ダッシュボードをダウンロードし、そして……たいていの場合、「No Data」と表示されます。なぜでしょうか?ルールには単一の標準がないため、唯一の選択肢はダッシュボードを編集するか、別のものを探そうとすることだからです。
しかしさらにあります。これらのメトリクスシステムはそれぞれ、カスタムクラス、つまりプラグインで設定できます。上の表を見てください。そう、設定は二つあります。一つは kafka プレフィックス付き、もう一つはなし。一つは metric の単数形、もう一つは metrics の複数形です。
そう、そのとおりなのです。
ねえ、もう 2026 年だよ、Kafka は OpenTelemetry を使えないの?
手短な答えはこうです。直接は使えません。しかし、Kafka に OpenTelemetry プロトコルを教えるいくつかの方法があります。
それを行う方法はいくつかあります。
- JMX Exporter と OpenTelemetry Collector の Prometheus レシーバーの組み合わせ——上で説明したのと同じ JMX マッピングの問題があります。
- OpenTelemetry Collector JMX レシーバー——依然として JMX ベースで、JMX の公開が必要であり、このコンポーネントは現在は非推奨とされ、代わりにスタンドアロンの JMX Gatherer Java プログラムを使うことが推奨されています。
- OpenTelemetry Java エージェント——良い選択肢です。JMX Metric Insight モジュールを通じて Kafka broker のメトリクスを収集でき、OpenTelemetry のデモも Kafka にこのアプローチを使っています。しかし、カスタムの JMX メトリクスのセットが欲しい場合は、結局また別のメトリクスマッピングファイルを抱えることになります。
解決策
上で説明したすべての問題に対処する何かがあったらどうでしょうか?
前述のとおり、metric.reporters と kafka.metrics.reporters の設定は単なるクラス名です。それらのクラスは、それぞれ org.apache.kafka.common.metrics.MetricsReporter と kafka.metrics.KafkaMetricsReporter のインターフェースを実装しなければなりません。
そこで私たちはこう考えました。次のような特徴を持つライブラリです。
ネイティブな OTLP、JMX の中継なし
ほとんどの Kafka 可観測性スタックは、jmx_exporter か類似のものを JVM エージェントとして取り付け、HTTP エンドポイント経由で MBean をスクレイプし、それを collector にプッシュします。
このプラグインは Kafka プロセスの内部に存在し、OTLP で直接 collector と通信します——プロセスが一つ減り、設定面が一つ減り、保守すべき JMX ルール YAML もありません。
一つのプラグインで、Kafka の両方のレジストリ
Kafka の broker は二つの並行するシステムを通じてメトリクスを公開します。metric.reporters で設定される Kafka SPI と、レガシーの Yammer/Coda Hale レジストリです。
UnderReplicatedPartitions、OfflinePartitionsCount、ActiveControllerCount、そして topic ごとの BrokerTopicMetrics といったいくつかの broker 内部シグナルは、Yammer にしか登録されません。
OtlpMetricReporter は、単一の設定で両方にアタッチします。同じ JAR がクライアント上でも変更なしで動作し、そこでは Yammer 側が自動的に無効になります。
設計によるフェイルセーフ——Kafka が決してブロックされない
metricChange や metricRemoval といったメトリクスコールバックは、メモリ内の ConcurrentHashMap に触れるだけです。すべての I/O はデーモンのスケジューラスレッド上で発生します。
collector に到達できない場合、エクスポート呼び出しはタイムアウトし、バッチは破棄され、次のティックはまっさらな状態で始まります。リトライキューも、無制限なメモリ使用も、Kafka の produce/fetch レイテンシへの影響もありません。
broker のコンテキストが一級の Prometheus ラベルになる
Kafka はクラスター ID、ノード/broker ID、そして Kafka のバージョンを伴って MetricsReporter.contextChange(MetricsContext) を呼び出します。
このプラグインはそれらの値を捕捉し、OTLP のリソース属性としてアタッチします。それらはすべての系列にラベル——kafka_cluster_id、kafka_node_id、kafka_broker_id——として現れるため、PromQL で by(kafka_cluster_id, kafka_node_id) が追加の配線なしで動作します。
皆さま、monedula-metrics-reporter のご紹介です
monedula-metrics-reporter は、これらの要件——そしてそれ以上——を満たすオープンソースライブラリです。
これは gRPC または HTTP を使って Kafka のメトリクスを OTLP 経由で直接エクスポートし、Java 17 以上で Kafka 3.x と 4.x をサポートし、同じパイプラインで JVM ランタイムメトリクスを出力することもできます。
また、次のような実用的な本番向け機能も含まれています。
- メトリクスの許可リスト(allow-list)、
- カスタムリソース属性、
- TLS および mTLS の設定、
- 圧縮、
- レポーター自身の自己監視メトリクス、
- そして broker とクライアントの両方のサポート。
レポーターは自身のヘルスメトリクスも出力します。たとえば次のようなものです。
monedula_reporter_export_success_total、monedula_reporter_export_failure_total、monedula_reporter_export_duration_ms。
つまり、collector のパイプラインが壊れたとき、ただ沈黙が返ってくるだけではありません。レポーター自身がエクスポートに失敗しているというシグナルが得られます。
このプロジェクトには、Kafka、OpenTelemetry Collector、Prometheus、Grafana を使った全体の流れを実演する使いやすいクイックスタートも付属しています。そして、ダッシュボードも問題の一部であるため、プラグインが生成するメトリクスに対応する、すぐに使えるよう厳選された Grafana ダッシュボードのセットも含まれています。
GitHub で見つけて、ローカルでビルドし、クイックスタートで試すことができます。ビルド済みの成果物も近日公開予定です。
バグを見つけたり改善の提案があれば、ぜひ GitHub で issue を作成してください。
まとめ
Kafka の監視が本来あるべき以上に難しいのは、Kafka が二つの異なるメトリクスシステムを通じてメトリクスを公開し、ほとんどの本番セットアップが今も JMX に依存し、そしてあらゆる JMX から Prometheus へのマッピングが broker、Prometheus、Grafana ダッシュボードの間にまた別の互換性レイヤーを生み出すからです。
monedula-metrics-reporter は異なるアプローチをとります。Kafka のメトリクスレポーターとして動作し、メトリクスを OTLP 経由でネイティブにエクスポートし、両方の Kafka メトリクスレジストリを扱い、出力されるメトリクスに対応するダッシュボードを同梱しています。
それで、Kafka のメトリクスはこんなに難しくなければならないのでしょうか?
願わくば、もうそんなことはありません。