深夜2時の呼び出し
時刻は午前2時14分。ナイトスタンドの上でバイブレーションを鳴らし続けるスマートフォンには、PagerDutyから「API Latency > 5s(APIレイテンシが5秒を超過)」というアラートが表示されています。真っ先にアプリケーションログを確認しましたが、特に異常は見当たりません。ウェブサーバーのCPU使用率も15%前後で安定しています。そこでデータベースのメトリクスを確認したところ、激しいロック競合が発生していました。意図しないマイグレーションスクリプトが、システムで最もアクティブなテーブルに対してメタデータロックを保持しており、リクエストが高速道路の玉突き事故のように積み重なっていたのです。
もし強固な監視スタックがなければ、その後2時間はログを追いかけ、原因を推測するだけで終わっていたでしょう。MySQL、PostgreSQL、MongoDBのいずれを使用していても、データベースには共通の性質があります。それは、アプリケーション全体が停止するまで「静かに」失敗し続けるということです。このガイドでは、PrometheusとGrafanaを使用した、実績のある監視パイプラインの構築方法を解説します。問題が深刻な障害に発展する前に、わずかな兆候の段階でキャッチすることを目指します。
クイックスタート:5分で稼働開始
すぐに可視化が必要な場合は、「エクスポーター(Exporter)」パターンを利用するのが最善です。Prometheusはデータベースと直接通信しません。その代わりに、データベースの内部情報をPrometheusが理解できる形式に変換する「エクスポーター」という小さなサイドカーサービスからメトリクスを収集(スクレイピング)します。
1. エクスポーターのデプロイ
PostgreSQLの場合は postgres_exporter、MySQLの場合は mysqld_exporter を使用するのが標準的です。以下は、データベースと一緒にPostgreSQLエクスポーターを即座に起動するための docker-compose.yml のスニペットです。
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: password123
postgres-exporter:
image: prometheuscommunity/postgres-exporter
environment:
DATA_SOURCE_NAME: "postgresql://postgres:password123@db:5432/postgres?sslmode=disable"
ports:
- "9187:9187"
2. Prometheusの設定
次に、prometheus.yml ファイルを更新します。これにより、Prometheusが数秒おきにどこへ生データを取りに行くべきかを指定します。
scrape_configs:
- job_name: 'postgres_metrics'
static_configs:
- targets: ['postgres-exporter:9187']
3. ダッシュボードのインポート
Prometheusがデータの収集を開始したら、Grafanaを開き、Prometheusをデータソースとして追加します。グラフを一から作成する代わりに、PostgresならダッシュボードID 9628、MySQLなら 7362 をインポートしてください。瞬時にデータベースの健康状態がライブ表示されます。
ディープダイブ:監視スタックの仕組み
ツールを起動するのは簡単ですが、トラブルシューティングを効果的に行うには、その背後にあるアーキテクチャを理解する必要があります。このシステムは、Prometheusが能動的なコレクターとして機能するプルベースのモデルに従っています。
エクスポーターの役割
エクスポーターは「翻訳機」として機能します。データベース内部の統計テーブルに対してSQLクエリを実行します。PostgreSQLでは pg_stat_activity を、MySQLでは performance_schema を参照します。これらのエクスポーターは /metrics エンドポイントを公開し、Prometheusが設定された間隔(通常は15〜60秒ごと)でそこからデータを取得します。
監視すべき重要なメトリクス
すべての変数を監視しようとする誘惑に負けてはいけません。冷静な判断を保つために、以下の「ゴールデンシグナル」に集中しましょう。
- 接続数(Connections):
max_connectionsの制限に近づいていませんか?DBが100接続を許可している場合に98に達すると、アプリケーションは即座に「Connection Refused(接続拒否)」エラーを吐き始めます。 - バッファキャッシュヒット率(Buffer Cache Hit Ratio): Postgresの場合、99%以上を目指すべきです。これが90%に低下すると、データベースはRAMではなくディスクから読み取りを行っていることになります。この変化により、1ミリ秒のクエリが100ミリ秒の悪夢に変わる可能性があります。
- トランザクションIDの周回(Transaction ID Wraparound / Postgres): これは究極のサイレントキラーです。この制限に達すると、データの破損を防ぐためにデータベースは文字通り書き込みを一切受け付けなくなります。
- スロークエリ(Slow Queries): 500ミリ秒以上かかっているクエリを追跡します。これらは通常、インデックスの欠落を示す最初の兆候です。
高度な活用法:カスタムメトリクスとアラート
標準的なエクスポーターはハードウェアの健康状態の把握には優れていますが、ビジネスロジックまでは把握できません。例えば、テーブル内に「未処理の決済」がいくつ滞留しているかを知る必要があるかもしれません。そこでのスパイクは、バックグラウンドワーカーが失敗している可能性を示唆するからです。
SQL Exporterによるカスタムクエリ
sql_exporter はこのような用途に最適です。GoやPythonのコードを一行も書かずに、任意のSQL SELECT COUNT(*) を Prometheus のゲージ(メトリクス)に変換できます。
# custom_queries.yml
jobs:
- name: "business_metrics"
interval: "1m"
queries:
- name: "unprocessed_orders"
help: "保留状態のままの注文数"
values: [count]
query: "SELECT count(*) as count FROM orders WHERE status = 'pending';"
アラートの設定
一日中画面を見つめていなければならないのであれば、監視は役に立ちません。Prometheus Alertmanagerに面倒な作業を任せましょう。以下は、アプリケーションがクラッシュする前に接続数の急増を検知するために私が使用しているルールです。
groups:
- name: database_alerts
rules:
- alert: HighConnectionCount
expr: pg_stat_database_numbackends > 80
for: 2m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} での高い接続数"
description: "データベース接続数が {{ $value }} に達しており、80% の容量を 2 分以上超えています。"
本番環境運用のための実践的なヒント
長年本番クラスターを管理してきた経験から、設定の不備がある監視システムは、監視が全くない状態と同じくらい危険であることを学びました。安全に運用するためのポイントを挙げます。
セキュリティを疎かにしない
エクスポーターは、メタデータに対する高度な読み取り権限を持って動作することが多いです。9187のようなエクスポーターのポートをパブリックインターネットに公開してはいけません。プライベートVPCやKubernetesのサイドカーパターンを使用して、Prometheusだけがエンドポイントに到達できるようにします。また、必ずエクスポーター専用の制限されたユーザーを作成してください。
-- PostgreSQL 10以降の場合
CREATE USER monitoring WITH PASSWORD '強力なパスワードを設定してください';
GRANT pg_monitor TO monitoring;
「オーバースクレイピング」の罠を避ける
高解像度なデータを得るために1秒ごとにスクレイピングしたくなるかもしれませんが、通常は過剰です。パフォーマンススキーマへのクエリは、CPUに測定可能な負荷を与えます。ほとんどの本番環境のワークロードでは、15秒または30秒の間隔で、クエリのパフォーマンスに影響を与えることなく十分な詳細を得ることができます。
ダッシュボード疲れを解消する
1つのページに50ものグラフが並んでいるチームをよく見かけます。いざインシデントが発生したとき、どのスパイクが重要なのか判断できず、思考停止に陥ってしまいます。Grafanaのダッシュボードは優先度別に整理しましょう。クラスターの正常・異常(Red/Green)ステータスだけを表示する「エグゼクティブサマリー」ダッシュボードを1つ用意し、詳細なトラブルシューティングが必要な場合にのみ「ディープダイブ」ダッシュボードへリンクするように構成します。
効果的な監視とは、結局のところ「より良い睡眠をとること」に尽きます。ボトルネックの検知を自動化すればするほど、午前2時に探偵ごっこをする時間は減っていきます。まずは基本的なエクスポーターから始め、アラートを調整し、トラフィック固有の癖を理解しながらシステムを洗練させていきましょう。

