「PostgreSQLの設定、とりあえず `max_connections` を増やしておけば安心だよね」
もしあなたが今、新人の頃の僕みたいにそんなことを考えているなら、ちょっとだけ手を止めて聞いてほしい。その設定、実はシステムの「時限爆弾」になっているかもしれないんだ。
今日は、現場で意外と見落とされがちな `max_connections` の真実と、パフォーマンスを最適化するための「大人の付き合い方」について、少し本音で語ってみるよ。
—
なぜ「増やすだけ」が危険なのか?
PostgreSQLにおいて、`max_connections` は同時に接続できるクライアントの上限を決める値だ。これを上げれば「接続エラー」は減る。でも、裏では何が起きているか。
PostgreSQLは、接続が一つ増えるごとに「プロセス(またはスレッド)」を一つ立ち上げるという、かなり贅沢な仕組みで動いているんだ。
1. メモリ消費の増大: 接続ごとに `work_mem` などが割り当てられ、メモリを食い合う。
2. コンテキストスイッチの地獄: CPUは、接続数が多すぎると「誰を処理するか」の切り替え(コンテキストスイッチ)に追われ、肝心のクエリ処理に割くパワーが削がれてしまう。
つまり、接続数を増やせば増やすほど、ある一定のラインを超えた瞬間から、DBの応答速度は雪崩を打つように悪化する。 これが「接続数は多いのに、なぜかクエリが遅い」という現象の正体さ。
—
「適切な数値」はどうやって決める?
現場でよくあるミスが「とりあえず 500 にしよう」「いや、1000 だ!」といった適当な見積もり。これ、一番やっちゃいけない。
基本的には、以下の式をベースに考えるのがセオリーだ。
> 接続数 = CPUコア数 × 2 + 有効なディスクスピンドル数
……と教科書には書いてあるけど、実務ではこれだけじゃ足りないことも多い。ここで重要になるのが「コネクションプーラー」の存在だ。
結論:接続は「貯める」のが正解
DBに直接数千の接続を貼るなんて、現代のアーキテクチャではナンセンス。PgBouncer のようなコネクションプーラーを前段に置くのが、今の「当たり前」だよ。
- アプリ側: たくさんの接続を貼りたがる(コネクションプーラーに投げる)
- PgBouncer: 大量の接続を受け取り、DBへの接続は「必要な分だけ」を効率よく使い回す。
これを使えば、DB側の `max_connections` は 100〜200 程度でも、アプリからは数千の同時リクエストを捌けるようになるんだ。
—
現場で役立つチェックコマンド
今まさに「うちのDB、接続数どうなってるんだ?」と気になった君へ。まずは今の状況を可視化してみよう。
— 現在の接続数と、上限に対する割合を確認する
SELECT
count() AS current_connections,
current_setting(‘max_connections’) AS max_connections,
round(100.0 count() / current_setting(‘max_connections’)::int, 2) AS usage_percent
FROM pg_stat_activity;
もし `usage_percent` が常に 80% を超えているなら、それは黄色信号だ。すぐに接続数を増やすんじゃなくて、まずは「本当にその接続数が必要か?」「アプリ側で接続を使い回せていない(close漏れしている)んじゃないか?」と疑うこと。
—
先輩からのアドバイス
僕が今まで見てきた中で、パフォーマンスが劇的に改善したケースのほとんどは「設定値をいじった」時じゃない。「無駄な接続を整理した」時だ。
- まずはアプリ側のコネクションプール設定を見直す: 接続を使い回せば、DBへの負荷は劇的に減る。
- 不要な `work_mem` を削る: 接続数を増やしたいなら、個々の接続が使うメモリを絞る勇気も必要。
- 監視を怠らない: `pg_stat_activity` を定期的に取得して、アイドル状態の接続が溜まっていないかチェックする習慣をつけてほしい。
`max_connections` は、DBというエンジンの「排気量」を決めるようなものだ。やみくもに大きくしても、車体(メモリやCPU)がついてこなければ走らない。
まずは今のシステムの「本当の姿」をデータで見るところから始めてみよう。何か詰まったら、いつでも聞いてくれ。一緒にログを読み解こうぜ。
コメント