Prometheus SQL Exporterでデータベースからビジネスメトリクスを直接監視する

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

上司からの「今日の売上は?」という質問と、手動SQLの悪夢

キャリアを始めたばかりの頃、私は少し滑稽な状況に陥ったことがあります。毎週月曜日の朝、上司から「週末に新規ユーザーが何人増えたか確認して。成約率はどう?」というメッセージが届くのです。そのたびに私はサーバーにSSHで入り、ターミナルで SELECT COUNT(*) を必死に叩いては、結果をExcelにコピー&ペーストして上司に送っていました。

その時、私は思いました。「CPUやメモリを監視するための立派なGrafanaがあるのに、なぜこれらのビジネス指標もダッシュボードに表示させないのだろう?」と。もしそれができれば、上司は画面を見るだけで済みますし、私も「人間レポート作成機」として働く代わりに、他の仕事に時間を割けるようになります。

しかし、開発チームは新機能のデッドラインに追われているのが常です。アプリケーションのコード一行一行にPrometheus Clientを組み込むために2〜3日も割く余裕はありません。そんな時、運用(Ops)担当者にとって「インスタント」でありながら非常に効果的な解決策となるのが、Prometheus SQL Exporterです。

なぜビジネスメトリクス取得のためにアプリのコードを修正すべきではないのか?

「教科書通り」のやり方は、コード内でPrometheusライブラリ(client_golangやclient_pythonなど)を使用することです。しかし、実際の導入では以下の3つの大きな壁にぶつかることがよくあります。

  • レガシーコード: コードが複雑すぎて、どこかに影響が出るのを恐れて誰も触りたがらない古いアプリケーション。
  • 開発リソースの消費: メトリクスの追加、テストケースの作成、デプロイ待ちに丸一週間かかることもあります。
  • 依存関係: 上司が新しい指標を追加したいと言うたびに、開発者にコードの修正、イメージの再ビルド、デプロイを依頼しなければなりません。

ビジネスデータは通常、MySQLやPostgreSQLなどのデータベーステーブルに既に存在しています。それなら、そこから直接取得したほうが早いのではないでしょうか?

一般的な解決策とそのデメリット

SQL Exporterに決める前に、いくつかの方法を試しました。

  1. PythonでCronjobを実行: スクリプトでDBをクエリし、結果をPushgatewayに送る方法です。最初はうまくいきますが、指標が50〜100に増えると、スクリプトの管理がメンテナンス上の悪夢になります。
  2. Telegraf SQL Inputを使用: 強力なツールですが、純粋なPrometheusエコシステムに慣れているチームにとっては、設定が少し煩雑に感じられるかもしれません。

最適なソリューション:Prometheus SQL Exporter

このツールは「通訳者」のような役割を果たします。データベースに接続し、定義したSQLコマンドを実行して、そのデータをPrometheusが取得できるように /metrics エンドポイントとして公開します。

最大のメリットは、アプリケーションのコードを一行も変更する必要がないことです。YAML設定ファイルを記述するだけで完了します。安定稼働しているシステムにとって、非常に安全な方法です。

ステップ1:データベースアカウントの準備

root アカウントは使用しないでください。セキュリティを確保するため、必要なテーブルに対して SELECT 権限のみを持つユーザーを作成します。

-- MySQLの例
CREATE USER 'sql_exporter'@'%' IDENTIFIED BY 'secure_password';
GRANT SELECT ON your_db.* TO 'sql_exporter'@'%';
FLUSH PRIVILEGES;

ステップ2:SQL Exporterの設定 (config.yml)

ここが最も重要な部分です。例えば、決済の遅延が発生していないかを確認するために、ステータスごとの注文数を監視する必要があるとします。

# config.yml
jobs:
  - name: "business_metrics"
    interval: '1m' # 60秒ごとにクエリを実行
    connections:
      - 'sql_exporter:secure_password@tcp(db_host:3306)/your_db'
    queries:
      - name: "orders_total"
        help: "ステータス別の注文合計数"
        labels:
          - "status"
        values:
          - "count"
        query: |
          SELECT status, count(*) as count 
          FROM orders 
          GROUP BY status;

SQL Exporterは自動的に結果を orders_total{status="completed"}orders_total{status="pending"} といったメトリクスに変換します。

ステップ3:Docker Composeによる迅速なデプロイ

Dockerを使用することで、バージョンの管理と環境の統一が容易になります。SQLクエリを更新する必要がある場合は、設定ファイルを修正してコンテナを数秒で再起動するだけです。

version: '3'
services:
  sql-exporter:
    image: burningalchemist/sql_exporter:latest
    volumes:
      - ./config.yml:/config.yml
    command:
      - "--config.file=/config.yml"
    ports:
      - "9399:9399"
    restart: always

実践的な経験:システムダウンを招きやすいミス

多くの大規模プロジェクトを通じて、サービスの中断を避けるための3つの教訓を得ました。

1. 大規模なテーブルでの重いクエリを避ける

最大の失敗は、適切なインデックスがない5,000万〜1億行のテーブルに対して COUNT(*) を実行することです。これにより、データベースのCPU使用率が瞬時に100%に達する可能性があります。
アドバイス: 常に EXPLAIN を使用してクエリを確認してください。テーブルが大きすぎる場合は、エンドユーザーに影響を与えないようスレーブ(リードレプリカ)に対してクエリを実行しましょう。

2. 高カーディナリティ(High Cardinality)に注意

メトリクスのラベルに user_idorder_id を含めないでください。ユーザーが100万人いる場合、Prometheusは100万個の異なる時系列(time series)を保存しなければならなくなります。これにより、わずか数時間でPrometheusサーバーのメモリが枯渇します。

3. データ取得の間隔(Interval)

ビジネスデータはCPUのように秒単位で更新する必要はありません。15秒ではなく、1分または5分に設定しましょう。これにより、データベースの負荷を軽減し、ダッシュボードの動作もスムーズになります。

まとめ

ニーズに応じて、適切なアプローチを選択してください。

  • 各関数のレイテンシ(遅延)を測定する必要がある場合:Prometheus Clientを使用します。
  • 売上やユーザー数を迅速に監視する必要がある場合:SQL Exporterが最良の選択肢です。

ビジネスメトリクスをGrafanaに表示させることは、運用チームの手を空けるだけでなく、技術チームの価値を高めることにも繋がります。経営陣にリアルタイムの売上ダッシュボードを提示できれば、チームの発言力は格段に強まるはずです。

Share: