上司からの「今日の売上は?」という質問と、手動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に決める前に、いくつかの方法を試しました。
- PythonでCronjobを実行: スクリプトでDBをクエリし、結果をPushgatewayに送る方法です。最初はうまくいきますが、指標が50〜100に増えると、スクリプトの管理がメンテナンス上の悪夢になります。
- 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_id や order_id を含めないでください。ユーザーが100万人いる場合、Prometheusは100万個の異なる時系列(time series)を保存しなければならなくなります。これにより、わずか数時間でPrometheusサーバーのメモリが枯渇します。
3. データ取得の間隔(Interval)
ビジネスデータはCPUのように秒単位で更新する必要はありません。15秒ではなく、1分または5分に設定しましょう。これにより、データベースの負荷を軽減し、ダッシュボードの動作もスムーズになります。
まとめ
ニーズに応じて、適切なアプローチを選択してください。
- 各関数のレイテンシ(遅延)を測定する必要がある場合:Prometheus Clientを使用します。
- 売上やユーザー数を迅速に監視する必要がある場合:SQL Exporterが最良の選択肢です。
ビジネスメトリクスをGrafanaに表示させることは、運用チームの手を空けるだけでなく、技術チームの価値を高めることにも繋がります。経営陣にリアルタイムの売上ダッシュボードを提示できれば、チームの発言力は格段に強まるはずです。

