web-dev-qa-db-ja.com

PDOで永続的な接続を使用することの欠点は何ですか

PDOでは、PDO::ATTR_PERSISTENT属性を使用して接続を永続化できます。 PHPマニュアルによると-

永続的な接続は、スクリプトの終了時に閉じられませんが、別のスクリプトが同じ資格情報を使用して接続を要求すると、キャッシュされて再利用されます。持続的接続キャッシュにより、スクリプトがデータベースと通信する必要があるたびに新しい接続を確立するオーバーヘッドを回避でき、Webアプリケーションが高速になります。

また、PDO ODBCドライバーを使用している間は、ODBC接続プーリングプロセスを妨げる可能性があるため、永続的な接続を使用しないことを推奨します。

したがって、最後の場合を除いて、PDOで永続的接続を使用することの欠点はないようです。ただし、このメカニズムを使用することで他の欠点があるかどうか、つまり、このメカニズムがパフォーマンスの低下などを引き起こす状況があるかどうかを知りたいと思います。

171
MD Sayem Ahmed

必ず 以下の回答 をお読みください。ここでは、ここで概説した問題を軽減する方法を詳しく説明しています。


PDOを使用すると、永続的な接続を行う他のPHPデータベースインターフェースと同じ欠点があります。データベース操作の途中でスクリプトが予期せず終了した場合、残った接続を取得する次のリクエストは、デッドスクリプトは中断されました。接続はPHPレベルではなく、プロセスマネージャーレベル(Apache for mod_php、FastCGIを使用している場合は現在のFastCGIプロセスなど)で開かれ、PHPは開かれませんスクリプトが異常終了したときに接続を切断するように親プロセスに指示しないでください。

デッドスクリプトがテーブルをロックした場合、それらのテーブルは、接続が終了するか、接続を取得する次のスクリプトがテーブル自体のロックを解除するまでロックされたままになります。

デッドスクリプトがトランザクションの途中にあった場合、デッドロックタイマーが作動するまで多数のテーブルをブロックできますが、それでもデッドロックタイマーは問題を引き起こしている古いリクエストの代わりに新しいリクエストを強制終了できます。

デッドスクリプトがトランザクションの途中にあった場合、その接続を取得する次のスクリプトもトランザクション状態を取得します。次のスクリプトが実際に既存のトランザクションをコミットしようとしたり、必要のないときにコミットしたり、必要のないときにロールバックしたりする可能性は、アプリケーションの設計によって異なります。

これは氷山の一角にすぎません。すべてのスクリプトリクエストでダーティな接続の後に常にクリーンアップを試みることにより、ある程度まで軽減できますが、データベースによっては苦痛になる場合があります。データベース接続の作成をスクリプトのボトルネックであると特定しない限り(これは xdebug および/または xhprof )、not永続的な接続を何かの解決策と見なすべきです。

さらに、ほとんどの最新のデータベース(PostgreSQLを含む)には、接続プールを実行する独自の方法がありますが、単純なVanilla PHPベースの永続的な接続のような直接的な欠点はありません。


ポイントを明確にするために、職場では永続的な接続を使用していますが、選択ではありません。アプリサーバーからデータベースサーバーへの初期接続が正確に3秒かかっていた奇妙な接続動作が発生していました。 1秒の何分の1かが必要でした。これはカーネルのバグだと思います。ランダムに発生し、オンデマンドで再現することができなかったため、トラブルシューティングの試行をあきらめました。また、アウトソースされたITには、それを追跡する具体的な能力がありませんでした。

とにかく、倉庫の従業員が数百個の入ってくる部品を処理しており、各部品が0.5秒ではなく3秒半かかっているとき、彼らが私たち全員を誘andして助けてくれる前に行動を起こさなければなりませんでした。そこで、私たちは自社開発のERP/CRM/CMSの怪物に少し触れて、永続的な接続のすべての恐怖を直接体験しました。一見ランダムに発生した微妙な小さな問題と奇妙な動作をすべて追跡するのに、週間かかりました。ユーザーがアプリから熱心に絞り出した1週間に1回の致命的なエラーが、ロックされたテーブル、放棄されたトランザクション、その他の不幸な不安定な状態を残すことが判明しました。

この悲しげなストーリーにはポイントがあります:パフォーマンスの名のもとに、決して壊すことのないものを壊しました。トレードオフはそれだけの価値はなく、ユーザーからの暴動なしに通常の接続に戻すことができます。

274
Charles

上記のチャールズの問題に応えて、

From: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

永続的な接続に関する一般的な不満は、再利用する前に状態がリセットされないことです。たとえば、開いているトランザクションと未完了のトランザクションは自動的にロールバックされません。ただし、接続をプールに入れてから再利用するまでの間に発生した承認の変更は反映されません。これは、望ましくない副作用と見なされる場合があります。それどころか、永続的な名前は、状態が永続するという約束として理解されるかもしれません。

Mysqli拡張機能は、持続的な接続の解釈、​​つまり状態が持続することと、再利用前の状態のリセットの両方をサポートします。デフォルトはリセットされます。永続的な接続が再利用される前に、mysqli拡張機能はmysqli_change_user()を暗黙的に呼び出して状態をリセットします。永続的な接続は、開いたばかりのようにユーザーに表示されます。以前の使用によるアーティファクトは表示されません。

mysqli_change_user()関数は高価な操作です。最高のパフォーマンスを得るために、ユーザーはコンパイルフラグMYSQLI_NO_CHANGE_USER_ON_PCONNECTを設定して拡張機能を再コンパイルすることができます。

安全な動作と最高のパフォーマンスを選択するのはユーザーに任されています。どちらも有効な最適化の目標です。使いやすさのために、最大のパフォーマンスを犠牲にして安全な動作がデフォルトになっています。

42
Prashant

永続的な接続は、データベースへの接続に(比較的)長い時間がかかる場合にのみ有効です。今日では、ほとんどそうではありません。永続的な接続の最大の欠点は、サイトを閲覧できるユーザーの数が制限されることです。MySQLが一度に10の同時接続のみを許可するように設定されている場合、11人目のユーザーがサイトを閲覧しようとしても機能しません。

PDOは永続性を管理しません。 MySQLドライバーがサポートします。 a)接続が利用可能で、ホスト/ユーザー/パスワード/データベースが一致する場合、接続を再利用します。変更があった場合、接続は再利用されません。最良の場合の最終的な効果は、サイトに別のユーザーがいるため、これらの接続が頻繁に開始および停止されることであり、それらを永続化しても効果はありません。

持続的接続について理解する重要なことは、ほとんどのWebアプリケーションでそれらを使用すべきではないということです。彼らは魅力的に聞こえますが、彼らは危険であり、ほとんど役に立たない。

これには他のスレッドもあると思いますが、リクエスト間で持続するため、持続的な接続は危険です。たとえば、リクエスト中にテーブルをロックしてからロック解除に失敗すると、そのテーブルは無期限にロックされたままになります。永続的な接続は、アプリの99%にとってはほとんど役に立ちません。なぜなら、異なる接続間で同じ接続が使用されるかどうかを知る方法がないからです。各Webスレッドには独自の永続的な接続のセットがあり、どのスレッドがどのリクエストを処理するかを制御する方法はありません。

PHPの手続き型mysqlライブラリには、mysql_connectへの後続の呼び出しが、異なる接続を開くのではなく、同じリンクを返す機能があります(予想どおり)。これは永続的な接続とは関係なく、mysqlライブラリに固有です。 PDOはそのような動作を示しません


リソースリンク: リンク

一般に、これを大まかな「ルールセット」として使用できます。

YES、永続的な接続を使用する場合:

  • データベースにアクセスするアプリケーション/ユーザーはほとんどありません。つまり、同じホストで200人の異なるユーザーが共有されているため、200のオープン(ただしおそらくアイドル)接続は発生しません。
  • データベースは、ネットワーク経由でアクセスしている別のサーバーで実行されています

  • (1つの)アプリケーションが頻繁にデータベースにアクセスする

NO、次の場合は永続的な接続を使用しないでください。

  • アプリケーションは、1時間に100回だけデータベースにアクセスする必要があります。

  • 1つのデータベースサーバーにアクセスする多数のWebサーバーがあります。

特にネットワークを介してデータベースにアクセスしている場合は、持続的接続の使用がかなり高速です。データベースが同じマシンで実行されている場合、それほど違いはありませんが、それでも少し高速です。ただし、名前が示すように、接続は永続的です。つまり、使用されていなくても開いたままです。

それに伴う問題は、「デフォルト構成」では、MySQLは1000個の並列「オープンチャネル」しか許可しないことです。その後、新しい接続は拒否されます(この設定を調整できます)。したがって、たとえば100クライアントごとに20台のWebサーバーがあり、それらのすべてに1時間に1ページしかアクセスできない場合、簡単な計算により、データベースへの2000の並列接続が必要であることがわかります。それは機能しません。

エルゴ:リクエストが多いアプリケーションにのみ使用します。

12
Jhonathan H.

テストでは、ローカルホストへの接続時間が1秒を超えていたため、永続的な接続を使用する必要があると仮定しました。さらにテストを行った結果、「localhost」に問題があることがわかりました。

秒単位のテスト結果(php microtimeで測定):

  • ホストされたWeb:connectDB:0.0038912296295166
  • localhost:connectDB:1.0214691162109(1秒以上:localhostを使用しないでください!)
  • 127.0.0.1:connectDB:0.00097203254699707

興味深いことに、次のコードは127.0.0.1を使用するのと同じくらい高速です。

$Host = gethostbyname('localhost');
// echo "<p>$Host</p>";
$db = new PDO("mysql:Host=$Host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
12

永続的な接続により、パフォーマンスが大幅に向上します。永続性を「回避」する必要があるという主張に同意しません。

上記の苦情は、誰かがMyIASMテーブルを使用し、テーブルロックを取得することで独自のバージョンのトランザクションをハッキングすることによって引き起こされているように聞こえます。 PDOのbeginTransaction()を使用して、テーブルをInnoDBに移動します。

6
Stephen

永続的な接続を持っていると、システムリソースを使い果たしてしまうようです。たぶん些細な量ですが、それでも...

2
Crayon Violent

永続的接続を使用することの説明は、他のデータベースと比較してMySQLの方がかなり高速であるという事実にもかかわらず、かなり高価な接続の量を明らかに削減しています。

永続的な接続に関する最初の問題...

1秒間に1000の接続を作成している場合、通常、非常に長い間開いたままになることを保証しませんが、オペレーションシステムはそうします。 TCP/IPプロトコルに基づいて、ポートを即座にリサイクルすることはできません。また、「FIN」段階で、リサイクルされる前にしばらく待機する必要があります。

2番目の問題...多くのMySQLサーバー接続を使用しています。

多くの人は、* max_connections *変数を増やしてMySQLとの100を超える同時接続を取得できることに気づかないだけで、他の人はMySQLと1024を超える接続を伝達できないという古いLinuxの問題に打ち負かされました。

Mysqli拡張機能で永続的接続が無効になった理由について説明します。永続的な接続を誤って使用し、パフォーマンスが低下するという事実にもかかわらず、これは主な理由ではありませんでした。実際の理由は次のとおりです-あなたはそれで多くの問題を得ることができます。

MySQLがそれほど難しくないMySQL 3.22/3.23の場合、永続的な接続がPHPに入れられたため、問題なく簡単に接続をリサイクルできます。しかし、それ以降のバージョンでは、大量の問題が発生しました–コミットされていないトランザクションがある接続をリサイクルすると、トラブルが発生します。カスタムキャラクターセットの構成で接続をリサイクルすると、セッション変数ごとに変換される可能性があるだけでなく、再び危険にさらされます。

永続的な接続を使用する場合の問題の1つは、実際にはそれほどうまくスケーリングできないことです。 5000人が接続している場合、5000の永続的な接続が必要です。永続性の要件を離れると、同じ量の接続を持つ10000人の人々にサービスを提供できる場合があります。なぜなら、彼らは彼らと一緒ではないときに個々の接続を共有する立場にあるからです。

1
Tony Stark

部分的な解決策は1回限りの接続のプールを持つことだろうかと思っていました。システムの使用率が低い限界に達すると、接続プールの作成に時間を費やし、完了またはタイムアウトしたときにそれらを配って殺すことができます。バックグラウンドでは、新しい接続が作成されるときに作成します。最悪の場合、リンクの確立が制限要因であると仮定して、これはプールなしで接続を作成するのと同じくらい遅いはずです?

0
James