背景とMySQL詳細監視が必要な理由
深夜2時にアプリケーションが504 Gateway Timeoutエラーを起こし、急遽ノートPCを開いて対応した経験はありませんか?焦ってSHOW PROCESSLIST;を実行しても、直前の5分間に何が起きていたのか分からず、強いもどかしさを感じたことがあるはずです。従来のスロークエリログの有効化やログファイルの手動解析といった手法は、初動が遅れるだけでなく、常に後手に回る運用を強いられます。
usersテーブルのレコード数が1,000万件を超えると、スロークエリが頻発するようになります。インデックスの追加は一時しのぎに過ぎません。根本的な課題は、インフラ全体に対する可視性の欠如にあります。InnoDB Buffer Poolの空き容量はどれくらい残っているのか?ディスクのIOPS負荷はどの程度か?コネクション数がmax_connectionsの上限に達したのはいつからなのか?
mysqld_exporter + Prometheus + Grafanaの3層構成は、これらの課題を包括的に解決します。
- mysqld_exporter: MySQLに隣接して独立稼働するデータ収集サービスです。内部ステータステーブルをクエリし、Prometheusフォーマットに準拠したメトリクスをHTTPエンドポイント経由で公開(expose)します。
- Prometheus: exporterから定期的にデータを取得(pull)して蓄積する時系列データベース(TSDB)です。事前定義したルールに基づき、継続的にアラートのトリガー判定を行います。
- Grafana: 膨大な数値データを直感的なグラフへと可視化し、TelegramやSlackなどの外部ツールへ即座に通知を送信するダッシュボードプラットフォームです。
監視ツールのインストールとセットアップ
鉄則として、exporterにMySQLのrootユーザーを使用してはいけません。セキュリティリスクを最小限に抑えるため、専用ユーザーを作成して必要最小限の権限(最小特権の原則)を付与します。
1. mysqld_exporter専用のMySQLユーザー作成
MySQLサーバーにログインし、権限設定スクリプトを実行します。
CREATE USER 'mysqld_exporter'@'127.0.0.1' IDENTIFIED BY 'MatKhauPhucTap@2026' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON performance_schema.* TO 'mysqld_exporter'@'127.0.0.1';
FLUSH PRIVILEGES;
重要な注意点: WITH MAX_USER_CONNECTIONS 3という制限は重要なフェイルセーフです。万が一exporterでクエリの遅延やプロセスのハングアップが発生しても、メインアプリケーション向けコネクションを3つ以上占有することはありません。
2. データベースサーバーへのmysqld_exporterのインストール
PrometheusのGitHubリポジトリからバイナリを直接ダウンロードします。
cd /tmp
wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz
tar -xvf mysqld_exporter-0.15.1.linux-amd64.tar.gz
sudo mv mysqld_exporter-0.15.1.linux-amd64/mysqld_exporter /usr/local/bin/
sudo useradd -rs /bin/false prometheus_exporter
認証情報を保護された設定ファイル/etc/.mysqld_exporter.cnfに保存します。
[client]
user=mysqld_exporter
password=MatKhauPhucTap@2026
host=127.0.0.1
port=3306
ファイルパーミッションを厳格に制限し、サービス用ユーザーのみにアクセスを許可します。
sudo chown prometheus_exporter:prometheus_exporter /etc/.mysqld_exporter.cnf
sudo chmod 600 /etc/.mysqld_exporter.cnf
3. systemdサービスユニットの作成
ユニットファイル/etc/systemd/system/mysqld_exporter.serviceを作成します。
[Unit]
Description=Prometheus MySQL Exporter
After=network.target mysql.service
[Service]
User=prometheus_exporter
Group=prometheus_exporter
Type=simple
ExecStart=/usr/local/bin/mysqld_exporter \
--config.my-cnf=/etc/.mysqld_exporter.cnf \
--collect.info_schema.innodb_metrics \
--collect.info_schema.processlist \
--collect.global_status \
--collect.global_variables
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
サービスを有効化して起動し、接続テストを行います。
sudo systemctl daemon-reload
sudo systemctl enable --now mysqld_exporter
# メトリクス出力を確認
curl -s http://localhost:9104/metrics | grep -E '^mysql_up'
出力結果にmysql_up 1と表示されれば、exporterがデータベースと正常に接続できていることが確認できます。
Prometheusの連携設定とアラートルール構築
メトリクスのエンドポイントが稼働したら、次はPrometheusサーバー側で収集対象(target)を登録し、インシデント検知用のアラートルールを策定します。
1. prometheus.ymlへのスクレイプジョブ追加
/etc/prometheus/prometheus.ymlに監視対象の設定を追記します。
scrape_configs:
- job_name: 'mysql_production'
scrape_interval: 15s
scrape_timeout: 10s
static_configs:
- targets: ['192.168.1.50:9104']
labels:
environment: 'production'
cluster: 'core-database'
運用のベストプラクティス: scrape_interval: 15s(15秒間隔)が最も安定したバランスの良い設定です。1〜2秒のような高頻度でスクレイピングを行うと、特に高負荷時においてデータベースへのメタデータ照会負荷が増加する原因になります。
2. 実践的なアラートルールの策定
運用現場に即したしきい値を設定した/etc/prometheus/alert_rules_mysql.ymlを作成します。
groups:
- name: mysql_critical_alerts
rules:
# MySQLインスタンス停止アラート
- alert: MySQLInstanceDown
expr: mysql_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "MySQLインスタンス {{ $labels.instance }} がダウンしています"
description: "1分以上にわたりMySQLインスタンスに接続できません。"
# コネクションプール枯渇アラート
- alert: MySQLTooManyConnections
expr: (mysql_global_status_threads_connected / mysql_global_variables_max_connections) * 100 > 85
for: 2m
labels:
severity: warning
annotations:
summary: "MySQLのコネクション高負荷: {{ $value | printf '%.2f' }}%"
description: "アクティブな接続数が許容max_connectionsの85%を超過しました。"
# InnoDB Buffer Poolのヒット率低下アラート
- alert: MySQLInnoDBBufferPoolHitRatioLow
expr: 100 - (rate(mysql_global_status_innodb_buffer_pool_reads[5m]) / rate(mysql_global_status_innodb_buffer_pool_read_requests[5m]) * 100) < 95
for: 5m
labels:
severity: warning
annotations:
summary: "InnoDBのキャッシュヒット率が低下: {{ $value | printf '%.2f' }}%"
description: "ヒット率が5分間連続で95%を下回りました。Buffer Poolのメモリ不足、またはフルテーブルスキャンを実行するクエリが多発している可能性があります。"
Grafanaダッシュボードによる可視化とモニタリング
Prometheusにデータが集約されたら、Grafanaを使って直感的な可視化ダッシュボードを構築します。
1. データソースの接続と既存ダッシュボードのインポート
- ブラウザからGrafanaにアクセスします(デフォルトポート:
3000)。 - Connections > Data Sourcesを開き、Prometheusを選択してPrometheusサーバーのアドレス(例:
http://prometheus-server:9090)を入力します。 - パネルを一から作成する手間を省くため、Dashboards > New > Importを開き、mysqld_exporter向けの人気コミュニティダッシュボードであるID 7362を入力して、作成したデータソースを紐付けます。
2. 監視すべき4つの重要メトリクス
ダッシュボード上には数多くのパネルが存在しますが、障害発生時や平常時の健全性維持において特に注視すべきは以下の4つのメトリクスです。
- Threads Running vs Threads Connected: たとえば
threads_connectedが500に達していても、threads_runningが15未満であれば、大半がアプリケーションプールのアイドル接続であるため安全な状態です。しかし、threads_runningがCPUコア数を大幅に超過した場合(例: 8 vCPU環境で40に達するなど)、テーブルロックや重いクエリの滞留によるボトルネックが発生しています。 - InnoDB Buffer Pool Hit Ratio: この指標は99%以上を維持するのが理想です。92〜94%付近まで低下している場合、
innodb_buffer_pool_sizeのメモリ容量が頻繁にアクセスされるホットデータを保持するのに不足しています。その結果、ディスクI/Oが頻発し、レスポンスタイムが数ミリ秒から数百ミリ秒へと跳ね上がります。 - Queries per Second (QPS) & Questions: 時間帯ごとのトラフィック負荷の傾向を正確に把握できます。アクセスが集中するピークタイム(例: 20時〜22時)を特定することで、負荷の高いバッチ処理(cronjob)やバックアップスクリプトの実行をオフピーク時に適切にスケジュールできます。
- InnoDB Log File Syncs: トランザクションログ(Redo Log)をディスクに同期書き込みする頻度を測定します。この数値とディスクI/Oキューが急増した場合は、
innodb_flush_log_at_trx_commitを1から2への変更を検討してください(予期せぬ電源喪失時に最大1秒分のデータ損失リスクを許容することで、I/O負荷を大幅に軽減できます)。
3. アラート検知の実機テスト
アラート機構が正しく機能しているか確認するため、ステージング環境でsudo systemctl stop mysqlを実行して意図的にサービスを停止してみましょう。1分経過後、GrafanaまたはPrometheusのAlerting画面を開き、MySQLInstanceDownルールがFiring状態に遷移したかを確認します。設定通りにTelegramやSlackへアラート通知が届けば、本番環境への投入準備は完了です。
