1. ホーム

MySQL接続がmax_user_connectionの制限を超える場合の対処法

2022-02-24 16:42:02
ユーザーデータベース名がすでに'max_user_connections'アクティブ接続エラーより多く、サイトがダウンしています。



max_user_connectionsはMySQLのユーザー接続の最大数で、文全体の意味は サーバー上のMySQL接続の最大数は十分に設定されていません。解決策 MySQL インストールディレクトリの my.ini または my.cnf ファイルで max_user_connections パラメータの値を変更し、MySQL サーバを再起動してください。







MySQLのデフォルトの最大接続数は100(N)であり、一般ユーザの実際の接続数はN-1しかなく、管理者を追い出さずに接続数がいっぱいにならないようにスーパー管理者用に1接続を予約しています。十中八九、接続数が上限を超えるのは、実際のサイト訪問者数ではなく、むしろサイト設計時に無理な設計アーキテクチャやデータ構造を使っているためだと思います。異常な接続制限の原因として考えられるのは、以下のようなものです(瞬時にまとめた天縁は、参考のため完全でない場合や誤りがない場合があります)。







<スパン 人数、オンライン時間、閲覧数などの統計が、メインプログラムのデータベースと同じデータ空間にあると楽ですね。



複雑な動的ページも発生しやすく、特にユーザーが1つのビューで複数のデータベースやテーブルの操作に関わる場合、そのような問題が発生します。



また、プログラム上のエラー(複雑な操作や待ち時間などがデータベースとのやり取りの途中に入るなど)、プログラム上のリリースバグもあります。



<スパン コンピュータのハードウェア構成が低すぎるが、MySQLの高すぎるバージョンと高すぎる構成がインストールされています。



キャッシュ技術を使用していない。



<スパン データベースが最適化されていない、またはテーブルの設計が複雑である。



したがって、このような問題が発生した場合は、まず、接続解除失敗の原因となるプログラムのバグがないかどうかを検討し、ハードウェアとソフトウェアの最適化を検討する必要があります。もちろん、MySQLの接続数を修正することもソフトウェア最適化の一つですので、学習する姿勢で自分なりの理由を研究して解決していただければと思います。もし、原因がわからないのであれば、まずは接続数の修正をして、本当の原因を突き止めるのを我慢するしかありません。







PHP のデータベース持続的接続 mysql_pconnect について



PHPプログラマは、彼らがMySQLデータベースに接続するためにmysql_pconnect(永続的な接続)関数を使用できることを知っている必要があります。 "あまりにも多くの接続で..."エラーメッセージ、サーバーと正常を再起動し、しばらくして再び同じ失敗をします。これらの問題の原因については、私は誰もが明確に言うことができる恐れている、PHPファイルにいくつかの関連情報がありますが、説明は理解することは容易ではない、ここで私は生意気に簡単な議論を行うことを試みる、ビューはすべて正しいとは限りません言及、あなたのフィードバックを歓迎します。







<スパン まず、永続的なデータベース接続の定義について見てみましょう。永続的なデータベース接続とは、スクリプトの実行が終了しても閉じられない接続のことです。永久接続の要求を受け取ると、PHP は同一の永久接続 (以前にオープンしたもの) がすでに存在するかどうかを調べます。存在する場合は、この接続を直接使用します。存在しない場合は、新しい接続が作成されます。同一の接続とは、同じホストに対して同じユーザー名とパスワードで接続することです。







PHP が MySQL と持続的接続で動作するためには、前提条件があります。PHPは、マルチスレッドあるいはマルチプロセスのWebサーバーのプラグインあるいはモジュールとしてインストールされる必要があります。最も一般的な方法は、マルチプロセスのApacheサーバーのモジュールとしてPHPを使用することです。マルチプロセスサーバーは、通常、親プロセスと、操作を調整する一連の子プロセスを持ち、子プロセスが実際にWebページを生成します。クライアントが親プロセスに要求を出すと、その要求は、他のクライアントの要求によってまだ占有されていない子プロセスに渡されます。つまり、同じクライアントが2回目にサーバーにリクエストを出したときは、別の子プロセスが処理する可能性が高いということです。恒久的な接続を開いた後、異なる子プロセスによって要求されたSQLサービスのその後のすべてのページは、すでに確立されたSQLサーバー接続を再利用することができます。これにより、各子プロセスは、ページが処理されるたびに SQL サーバーへの接続要求を行うのではなく、その存続期間中に一度だけ接続操作を行うことができるようになります。PHP 自身はデータベース接続プールを持ちませんが、Apache にはプロセスプールがあり、Apache の子プロセスは終了時にプロセスプールに戻されます。つまり、mysql_pconnect で開いた mysql 接続リソースは解放されず、対応する Apache サブプロセスでプロセスプールにアタッチされています。そして、それは次の接続要求のために再利用することができます。すべてうまくいっているように見えますが、Apache への同時アクセスが多いときに mysql_pconnect を使用すると、前の Apache 子プロセスによって占有された MySQL 接続が閉じられなくなり、それによって MySQL がすぐに最大接続数に達して、その後の要求が応答しなくなる可能性があります。







上記の文章はPHPのドキュメントから一部抜粋したもので、まだ少し文字数が多くてわかりにくいかもしれませんので、別の例を平易に説明しておきます。







Apacheが最大接続数1000、MySQLが最大接続数100で構成されていると仮定すると、Apacheサーバーが200の同時アクセスを受けたとき、そのうち100はデータベースアクセスを伴い、残りの100はこの時点では利用できるデータベース接続がないためデータベースアクセスを伴わない、となります。ということで、ここでデータベースアクセスに関わる100 これらの操作が終わらないと、他の接続は再びデータベース接続を得ることができず、これらの操作が終わると、対応する接続はプロセスプールに入れられ、この時、Apacheのプロセスプールには200の空きサブプロセスが存在することになります。そのうち100個はデータベース接続を持つもので、Apacheはアクセス要求に対してランダムに空きサブプロセスを選択するので、取得するサブプロセスはデータベース接続を持たない100個のうちの1個である可能性が高く、データベース接続は上限に達しているので、うまく新しいデータベース接続を確立できないため、ページを更新し続けなければならず、運良くデータベース接続を持つサブプロセスを割り当てられたときには ページを更新し続け、運悪く、データベース接続を持つサブプロセスが割り当てられ正常にページをブラウジングすることができるようになるのだそうです。サイトの訪問者が多い場合、常に多くの同時処理が発生するため、訪問者がデータベースへの接続が不可能であることを発見し続ける可能性があります。







<スパン ApacheとMySQLの最大接続数を同じにすることです。たしかに、この最大接続数を適度に調整すれば、この問題はなんとか回避できるのですが、ApacheとMySQLの負荷容量が違うので、Apacheの負荷容量に合わせて設定すると、MySQLにとっては、この最大接続数が大きい側になり、MySQLデータベースへの永久接続数が大量に発生し、たとえば平時で数百万の軍隊を挙げるようなものなのです。Mysqlの負荷容量に合わせて設定すると、Apacheにとっては最大接続数が小さくなり、鶏と卵のような感覚になり、Apacheの最大効率を引き出せない。







というわけで、PHPのマニュアルによると、データベース常時接続を使うのは同時アクセス数の少ないWebサイトのみで、同時アクセス数の少ないWebサイトでは、データベース常時接続を使うことでもたらされる効率化はあまり意味がないようです、この点から、PHPでのデータベース常時接続は基本的に鶏卵役だと思います、もし、どうしてもデータベース接続プーリングという概念を使いたいなら、sqlrelayやApache独自のmod_dbdを試せば、驚くかもしれませんね。







mysql_free_resultとmysql_closeについて



これまでのmysqlでは、mysql_store_resultを一度呼び出してデータを取得し、その後直接呼び出すというショートリンクを使用していたのですが、この方法では、mysql_store_resultを呼び出すことができません。



コードは以下の通りです。




mysql_free_result(m_result);



mysql_close(m_Database);




<スパン しかし、2つの問題があります。







<スパン 長い接続 (接続後、決して閉じない) を使用する場合、最後に mysql_close が呼ばれるなら、毎回 mysql_free_result を呼び出す必要がありますか?



mysql_closeが呼ばれたとき、m_resultのデータはまだ利用可能ですか?



<スパン まず、結論から。







毎回呼び出す必要があります。なぜなら、テストの結果、mysql_store_result へのポインタは毎回異なるので、同じ buf を共有していない。



まだ動きます。valgrind スキャンの後、mysql_close のみの呼び出しの結果が



コードは以下の通りです。




<スパン ==9397== 1 ブロック中の 16,468 (直接 88、間接 16,380) バイトが消失記録 4 of 5 で確実に失われる



==9397== at 0x40219B3: malloc (vg_replace_malloc.c:195)



==0x8053EA2: my_malloc (in /data/home/dantezhu/appbase/application/platform/openqqcom/share/db_openright/test/test)



0x806D314: mysql_store_result (in /data/home/dantezhu/appbase/application/platform/openqqcom/share/db_openright/test/test) による ==9397== 。



0x804BB04: CMySQLCppClient::Result(st_mysql_res*&) (mysql_cpp_client.cpp:127) による ==9397== 。



==9397== by 0x804AB58: CDBOpenRight::GetUinsByApp(unsigned int, std::set<unsigned int, std::less<unsigned int>, std::allocator< unsigned int> >&) (db_openright.cpp:58)。



0x8049F10 によって ==9397==: main (test.cpp:27)