「沈黙」するデータベースという悪夢
夜中の2時にウェブサイトが重いと叩き起こされ、データベースが何の説明もなく「ブラックボックス」のように沈黙していた経験はありませんか?駆け出しの頃、私の唯一の反応はサーバーにSSHで入り、topやhtopを闇雲に打ち込み、iotopでディスクが悲鳴を上げていないか確認することでした。もしすべてが正常(緑色)なら、今度は数GBものログファイルをgrepしてスロークエリを探す羽目になります。このやり方は苦労が多い割に、運任せな部分が大きすぎました。
正直なところ、PrometheusとGrafanaのコンビで半年間戦ってみて、ようやくデータの可視化(オブザーバビリティ)の価値が分かりました。ダッシュボードがあるのは、速度計や温度計がすべて揃った車を運転するようなものです。本番環境のあらゆる指標が数値として明確に表示され、「なんとなくDBが重い気がする」といった曖昧な表現をする必要はもうありません。
監視ソリューションの比較検討
Prometheus Exporterという結論に至る前に、いくつかの選択肢を検討しました:
- クラウド標準サービス(CloudWatch, Azure Monitor): 数クリックで導入できるので非常に楽です。しかし、高い頻度で詳細なカスタムメトリクスを監視しようとすると、月末の請求額に驚くことになります。
- Zabbix/Netdata: Zabbixはアラート機能は優秀ですが、ダッシュボードのUIが少し「レトロ」です。時系列データのカスタマイズも大きな壁となります。NetdataはOSレベルで詳細すぎ、必要な情報がノイズに埋もれてしまうことがありました。
- Prometheus Exporter: これが私にとって最適な選択でした。ExporterはMySQLの
performance_schemaやPostgresのpg_stat_activityに直接クエリを投げます。OSレベルでは決して到達できない「深部」の指標を取得できるのです。
Exporterのメリットとデメリット
メリット:
- 内部指標のキャプチャ:バッファプールのヒット率、トランザクションロック、レプリケーション遅延などを秒単位で正確に把握できます。
- システムリソースの消費が非常に少ない(オーバーヘッドが極めて低く、CPU使用率はわずか1-2%程度)。
- 強力なコミュニティサポート。既存のGrafanaダッシュボードテンプレートをインポートするだけで、すぐに使い始められます。
デメリット:
- サーバーに追加の小さなエージェントをインストールするか、サイドカーコンテナを実行する必要があります。
- Exporterがリスンしているポートに対して、厳密なセキュリティ設定を管理する必要があります。
mysqld_exporterでMySQL監視を始める
安全性を確保するため、決してrootユーザーを使用してはいけません。Exporterが動作するために必要な最小限の権限を持つ専用のMySQLユーザーを作成すべきです。
-- 安全な監視用ユーザーの作成
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'MatKhauSieuKho123' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
FLUSH PRIVILEGES;
シンプルに管理したい場合は、Docker Composeを使いましょう。この方法なら、バージョン管理や環境構築が非常に簡単になります。
# docker-compose.yml
services:
mysql-exporter:
image: prom/mysqld-exporter
container_name: mysql-exporter
environment:
- DATA_SOURCE_NAME=exporter:MatKhauSieuKho123@(mysql-host:3306)/
ports:
- "9104:9104"
restart: always
ヒント: スロークエリを効果的に監視するには、slow_query_logが有効になっていることを確認してください。Exporterはinformation_schemaからデータを取得し、グラフを描画してくれます。
postgres_exporterでPostgreSQL監視を設定する
PostgreSQLにおいて、その威力はStats Collectorにあります。私はよくpg_stat_statementsを組み合わせて、リソースをもっとも「食っている」クエリの根本的な原因を突き止めます。
-- postgresql.confにこの行を追加してDBを再起動
shared_preload_libraries = 'pg_stat_statements'
-- その後、exporter用のユーザーを設定
CREATE USER postgres_exporter PASSWORD 'MatKhauSieuKho123';
ALTER USER postgres_exporter SET SEARCH_PATH TO postgres_exporter,pg_catalog;
GRANT pg_monitor TO postgres_exporter;
以下の1つのコマンドでPostgres用Exporterを起動できます:
docker run -d \
--name postgres-exporter \
-e DATA_SOURCE_NAME="postgresql://postgres_exporter:MatKhauSieuKho123@db-host:5432/postgres?sslmode=disable" \
-p 9187:9187 \
prometheuscommunity/postgres-exporter
見逃せない4つの「ゴールデンメトリクス」
度重なる「火消し」作業を経て、私がダッシュボードの最も目立つ場所に常に配置している指標のリストがこちらです。
1. コネクションプール(接続数)
active_connectionsがmax_connectionsの90%に達すると、システムはユーザーの接続を拒否し始めます。私は致命的な事態になる前に対応できるよう、通常80%でアラートを設定しています。
2. スロークエリ(実行時間の長いクエリ)
数だけでなく、トレンドに注目してください。デプロイ後に100ms以上かかるクエリが急増した場合、開発チームがどこかでインデックスを貼り忘れた可能性が高いです。
3. レプリケーション遅延
マスター・スレーブ構成において、遅延は死活問題です。スレーブが5〜10秒以上遅れると、ユーザーが見るデータが古くなってしまいます。MySQLではseconds_behind_masterという指標を注視しましょう。
4. キャッシュヒット率
健全なデータベースは、キャッシュヒット率が95%以上である必要があります。この数値が低下している場合、DBがディスクから頻繁に読み出しを行っていることを意味します。この段階では、メモリの増設は避けて通れない解決策となります。
実例紹介:1つのクエリが「ハング」してディスクが50GB膨れ上がった話
以前、postgres_exporterのグラフのおかげで、あるトランザクションが2時間もの間「Idle in transaction」状態になっているのを発見しました。それがロックを保持し続けていたため、Auto-vacuumプロセスがクリーンアップを行えず、DBの容量がたった一晩で50GBも膨れ上がってしまいました。通常のps auxコマンドだけで確認していたら、間違いなくこのエラーを見逃していたでしょう。
私からのアドバイスは、「障害が起きてから監視を入れるのではなく、今すぐステージング環境から導入せよ」ということです。毎日グラフを眺めることでデータベースの「呼吸」を理解でき、システムがダウンする前にリソースをスケールすべきタイミングを予測できるようになります。
最後に、数値を把握することは開発チームとのやり取りにおいて自信に繋がります。「DBが少し重い気がします」と言う代わりに、「クエリXがIOPSの40%を占有しており、スレーブ側に5秒の遅延が発生しています」と伝えましょう。その方がずっとプロフェッショナルで説得力がありますよね?
