コンテンツへスキップ
DedicatedPHP 接触

PHPのデータベース接続枯渇:診断と復旧

接続枯渇と遅いクエリを見分け、PHPの同時実行数を測定し、上限をむやみに引き上げずに処理能力を回復する方法を解説します。

PHPプロセス、同時接続、データベースの接続上限を示す技術図

PHPでのデータベース接続枯渇は、多くの場合、断続的なエラーとして現れます。一部のリクエストは失敗し、ほかのリクエストは待ち続け、負荷の高い時間帯には問題が悪化します。接続上限を引き上げれば一時的に緩和できますが、データベースサーバー側に飽和を移すおそれもあります。解決には、どのリソースが枯渇しているのか、誰が接続を占有しているのかを特定することが第一歩です。

症状を把握し、障害範囲を絞り込む

症状を把握し、障害範囲を絞り込む — guía visual de DedicatedPHP

「too many connections」、接続確立の失敗、タイムアウト、最大実行時間を超過したリクエストなどのエラーを確認します。発生頻度をトラフィックやほかの指標と照合してください。指標には、アプリケーションのレイテンシ、CPUとメモリの使用率、データベースのエラー、リクエストの処理時間などがあります。

負荷が高いときと低いときの違いが、最初の手掛かりになります。ピーク時にエラーが発生し、トラフィックが減ると消える場合は、同時実行数の上限が原因かもしれません。リクエストが少なくても続く場合は、接続の保持、プロセスのブロック、長時間実行されるクエリ、データベースへのアクセス不能を調べてください。同じ上限をほかのサービスも共有していないかも確認します。接続を消費しているのがPHPだけとは限りません。

接続枯渇と遅いクエリ、ロックを区別する

これらは関連していますが、同じ問題ではありません。接続枯渇は、新たな接続を確立するための空き枠がない状態です。遅いクエリは接続を長時間占有し、積み重なると枯渇を引き起こすことがあります。ロックが発生すると、別のトランザクションがリソースを解放するまでクエリが待機します。利用不能とは、より広範な原因によってデータベースが接続を受け付けられない、または処理できない状態です。

エラーメッセージと障害発生箇所を確認してください。クエリ実行前にリクエストが失敗する場合は、接続の確立処理と到達した上限を調べます。接続後に時間がかかる場合は、実行中のクエリ、その処理時間、待機、開いたままのトランザクションを確認します。アプリケーションの応答が遅いからといって、「接続が足りない」と決めつけないでください。枠を増やしても、高コストなクエリやロックは解消されません。

PHPの同時実行数とデータベースの上限を関連付ける

リクエストを処理するプロセスを用いる一般的なPHPの構成では、各プロセスはデータベース処理中に接続を必要とすることがあります。潜在的な需要は、同時に稼働できるプロセス数、各プロセスが開く接続数、接続を保持する時間によって変わります。バックグラウンドジョブ、コンソールコマンド、その他のサービスが使用する接続も数に含めてください。

最悪のケースを保守的に見積もります。各プロセス群の実効的な最大同時実行数に、各プロセスが同時に使用する接続数を掛け合わせ、データベースを共有するほかの利用者分を加算します。その合計を設定済みの上限と照合し、管理操作や負荷変動に備えて余裕を確保してください。各リクエストが常に1接続に相当すると仮定してはいけません。接続のライフサイクルは、データベースクライアント、設定、利用パターンによって異なります。

負荷の分散方法も確認してください。複数のPHPインスタンスがそれぞれローカルの上限を守っていても、合計ではデータベースの接続枠を超えることがあります。水平スケーリングは潜在的な同時実行数を増やします。接続総数を再計算しないままでは、安全な緩和策とはいえません。

両側から計測する

タイムスタンプを使って、アプリケーションとデータベースのメトリクスを関連付けます。PHPでは、リクエスト処理時間、接続エラー、タイムアウト、ビジー状態のプロセス数を記録します。データベースでは、アクティブ接続数と最大接続数、接続拒否、実行中のクエリ、セッションの経過時間、エンジンで確認できる待機状態を調べます。

認証情報、接続文字列全体、クエリの機密データは記録しないでください。エンジンがセッションや状態を識別できる場合は、その情報を使って、アイドル状態の接続、実行中のクエリ、保留中のトランザクションを区別します。両側のログを照合してください。PHPプロセスがビジーな時間帯と接続数の急増が同時に起きていれば、同時実行数が原因と考えられます。長時間残っているセッションやアイドル状態のプロセスが多い場合は、接続の保持が疑われます。少数の長時間クエリでも、接続枠が徐々に消費される原因になり得ます。

計測によって、次の3つの問いに答えられるようにします。接続が何本使われているか、どれくらいの時間使われているか、どの処理が接続を占有しているか。時間軸に沿ったデータがなければ、上限変更や永続的接続の有効化によって変数が増え、原因の特定が難しくなります。

永続的接続と長時間接続を評価する

永続的接続は、特にリクエスト間でプロセスが維持される環境で、接続を繰り返し確立するコストを削減できます。ただし、プロセスに関連付けられた接続が残り、クエリを実行していなくても接続枠を占有することがあります。プロセス数やインスタンス数が多い場合、保持された接続の合計がデータベースの上限に達する可能性があります。

有効化または無効化する前に、プロセスとドライバーの実際のライフサイクルを確認してください。セッションがどのように再利用されるか、またリクエスト間でアプリケーションがトランザクション、セッション変数、接続固有の設定など、必要な状態をリセットするかを検証します。永続的接続は汎用的な接続プールではなく、消費量の削減を保証するものでもありません。実際の負荷を再現した条件でテストし、最大接続数、レイテンシ、残存状態を観察してください。

根拠に基づき、段階的に緩和する

  1. 同時実行数を制限する。共有される接続枠に需要が収まるよう、PHPのプロセス数やワーカーの並列度を調整します。需要への圧力は下がりますが、処理能力が継続的な需要を下回ると、キューやレイテンシが増える可能性があります。
  2. 不要になったリソースを解放する。ライブラリと実行パターンが許す場合は接続を明示的に閉じ、データベースと無関係な処理中に接続を保持しないようにします。ただし、永続的接続を閉じても、サーバー側の物理接続が必ず解放されるとは限りません。結果はドライバーとプロセスのライフサイクルによって異なります。開いたままのトランザクションや、クリーンアップを完了しないエラー経路を確認してください。
  3. 接続の占有時間を短縮する。遅いクエリ、インデックス、取得するデータ量、トランザクションを分析します。接続を長時間保持する処理を最適化すれば、上限を引き上げずに同時接続需要を減らせる可能性があります。
  4. 計測後にのみ上限を調整する。データベースにCPUとメモリの余力があり、新たな最悪ケースを持続可能であれば、最大値の引き上げが妥当な場合があります。そうでなければ、処理の蓄積を許し、飽和を悪化させます。

一度に1つの変更を適用し、変更前の状態を記録して、ロールバック条件を定めてください。すでにシステムに影響が出ている場合は、すべてのプロセスを一度に再起動すると新たな接続急増を招くおそれがあるため、一時的に同時実行数を減らすほうが安全なことがあります。

接続プールやプロキシを検討するタイミング

接続プールやプロキシは物理接続を再利用し、データベースエンジンに到達する接続数を制御できます。短命な接続を使うアプリケーションプロセスが多数ある場合に有効です。ただし、同時実行される処理がなくなるわけでも、クエリが高速化するわけでもありません。容量、キュー、上限、独自の動作モードを持つ別のレイヤーが加わります。

導入前に、データベースエンジン、PHPドライバー、認証、トランザクションの使用方法、セッション状態との互換性を確認します。長時間接続、再接続、プロキシ障害の管理方法を調べ、運用に必要なメトリクスと手順を定めてください。実際の同時実行数を反映したテストで検証します。開発環境で動作する設定が、高負荷時にも同じように動作するとは限りません。

復旧に備え、再発を防ぐ

復旧に備え、再発を防ぐ — guía visual de DedicatedPHP

接続数が上限に近づいたとき、接続拒否、クエリ処理時間、PHPプロセスの飽和を検知するアラートを設定します。インスタンス、バックグラウンドジョブ、その他の利用者を含む実際の負荷を再現したテストを追加し、平均値だけでなく最悪のケースを確認してください。何を計測するか、同時実行数をどう制限するか、誰が接続枠を変更できるか、いつロールバックするかを明記した運用手順を整備します。

サービス復旧後は、インシデント直前の経緯を確認します。トラフィックの変化、デプロイ、新たなクエリ、プロセス数の増加、クリーンアップの失敗などを調べてください。目的はデータに基づいて原因と結果を結び付けることです。メトリクスが接続の保持を示しているならライフサイクルを修正し、クエリの処理時間が主因ならクエリを最適化します。正当な同時実行需要が処理能力を上回る場合は、明示的な接続予算を定めて、容量を適切に設計し、同時実行数を制限してください。

これらのアイデアをあなたのプロジェクトに活用してみませんか?あなたのPHPプラットフォームについて話し合いましょう。
関連サービスを見る