午前2時の電話と「無機質な」数字たち
真夜中、デスクの上でスマートフォンが激しく震えました。Slackは 504 Gateway Timeout の通知で溢れかえっています。アプリケーションログを確認すると、Connection pool exhausted というエラーが延々と続いていました。急いでサーバーにSSHで入り、top コマンドを叩くと、CPU使用率は90%に跳ね上がっています。しかし、どのクエリがリソースを食いつぶしているのか、いくつのトランザクションがハングしているのか、全く分かりませんでした。
その時の感覚は、まるでヘッドライトなしで霧の中を高速走行しているようでした。もし十分な監視システムがあれば、1時45分の時点でコネクション数の急増に気づき、システムが「崩壊」する前に対処できていたはずです。この記事は、そんな苦い経験から得た教訓をまとめ、PostgreSQLに鋭い「目」を持たせるためのガイドです。
クイックスタート:5分でダッシュボードを構築
迅速なデバッグやテストには、Docker Composeが最適です。一つの設定ファイルだけで、複雑なインストール作業なしに監視スタック全体を構築できます。
# docker-compose.yml
version: '3.8'
services:
postgres_exporter:
image: prometheuscommunity/postgres-exporter
environment:
DATA_SOURCE_NAME: "postgresql://user:password@your_db_ip:5432/postgres?sslmode=disable"
ports:
- "9187:9187"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3000:3000"
次に、データを取得するための最小限の設定を記述した prometheus.yml ファイルを作成します:
scrape_configs:
- job_name: 'postgres'
static_configs:
- targets: ['postgres_exporter:9187']
docker-compose up -d コマンドを実行します。これで、exporterがメトリクスの収集を開始し、Prometheusに送信され、ポート3000のGrafanaで可視化する準備が整います。
動作の仕組み:postgres_exporterの役割
PostgreSQLは、デフォルトではPrometheusが要求する時系列(time-series)形式でデータを出力しません。そこで postgres_exporter が「通訳」の役割を果たします。データベースにアクセスし、SELECT * FROM pg_stat_activity などのSQLコマンドを実行して、その結果をコンピューターが理解できるメトリクスに変換します。
セキュリティのための専用ユーザー設定
本番環境の監視に postgres アカウント(スーパーユーザー)を絶対に使用しないでください。安全性を確保するために、権限を制限した専用ユーザーを作成すべきです:
-- 監視専用ユーザーの作成
CREATE USER monitoring WITH PASSWORD 'your_secure_password';
-- システム統計テーブルへのアクセス権限を付与
GRANT pg_monitor TO monitoring;
見逃せない4つの「ゴールデン」指標
何百ものグラフに圧倒されないでください。システムの健康状態を真に反映する重要な数値に集中しましょう:
- Connections: 実際の接続数と
max_connectionsを比較します。この数値が80%に達している場合、システムは危険水域にあります。 - Transaction Throughput: Commit/Rollbackの比率を監視します。Rollbackが急増(例:5%以上)した場合、アプリケーションコードのロジックエラーやデータ競合が発生している可能性があります。
- Buffer Cache Hit Ratio: RAMから読み取られたデータの割合です。この数値は95%以上を維持する必要があります。80%まで低下すると、ディスクI/Oが10倍に跳ね上がり、DBの速度が目に見えて低下します。
- Database Size & Bloat: テーブルの肥大化を監視します。Autovacuumプロセスが効率的に動作していない場合、10GBのテーブルに最大4GBの「ゴミ」(デッドタプル)が含まれる可能性があります。
運用中、レポート作成のためにSQLデータを他の形式に素早く書き出す必要があることがよくあります。私はよく toolcraft.app の CSVからJSONへの変換ツール を利用しています。ブラウザ上で処理されるため、機密データが第三者のサーバーに漏れる心配がないのがメリットです。
アラートの設定:安眠を確保するために
ダッシュボードは、それを見ている時にしか役に立ちません。しかし、24時間365日画面に張り付いているわけにはいきません。アラート設定こそが、致命的な事態になる前に迅速な対応を可能にする「番人」となります。
アラートルールの設定例
アラートの閾値を定義するために alert_rules.yml ファイルを作成します:
groups:
- name: postgres_alerts
rules:
- alert: PostgresHighConnections
expr: pg_stat_database_numbackends > (pg_settings_max_connections * 0.8)
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} でDBのコネクションが不足しています"
description: "接続数が5分間連続で制限の80%を超えました。"
- alert: PostgresDown
expr: pg_up == 0
for: 1m
labels:
severity: fatal
annotations:
summary: "PostgreSQLがダウンしました!"
description: "インスタンス {{ $labels.instance }} に接続できません。すぐに確認してください!"
SlackやTelegramと連携させれば、コネクションが増え始めた瞬間に通知を受け取ることができます。完全にハングアップしたDBを救出するよりも、この段階で「アイドル状態のコネクション(idle connections)」を整理する方がはるかに簡単です。
導入における実戦的なアドバイス
大規模システムのトラブルシューティングを何度も経験した結果、いくつかの重要な注意点をまとめました:
- コミュニティのダッシュボードを活用する: ダッシュボードをゼロから自作しないでください。Grafana Labsにアクセスし、ダッシュボードID
9628をインポートしましょう。これはコミュニティで最も信頼され、標準化されているものです。 - データ取得の間隔 (Scraping Interval): 1秒間隔などの短すぎる設定は避けてください。メトリクスの取得は、その都度DBへのクエリ実行を伴うからです。15〜30秒の間隔が、精度とパフォーマンスの完璧なバランスです。
- ハードウェアも同時に監視する: DBの低速化は、ディスクI/Oのボトルネックが原因であることも多いです。
node_exporterを追加でインストールし、サーバーのCPU、RAM、ディスク遅延(latency)も並行して監視しましょう。 - pg_stat_statements の併用: Prometheusは「DBが遅いこと」を教えてくれますが、
pg_stat_statementsは「どのSQLが犯人か」を正確に示してくれます。このエクステンションを有効にして、データを深掘りしましょう。

