エラー2006:MySQLサーバーが廃止されました


8

CentOSサーバーでuWSGIとnginxを使用してPython Pyramidアプリを実行しています。SQLAlchemyをORMとして、MySQLdbをAPIとして、MySQLをデータベースとして使用しています。サイトはまだ稼働していないため、トラフィックは私と会社の他の従業員だけです。データベースにデータを追加するためにデータを購入したため、最大(かつ最も頻繁に照会される)テーブルは最大150,000行です。

昨日、ウェブサイトの4つの新しいタブを連続して開いたところ、502のBad Gatewayエラーがいくつか返されました。uWSGIログを調べたところ、次のことがわかりました。

sqlalchemy.exc.OperationalError: (OperationalError) (2006, 'MySQL server has gone away') 'SELECT ge...

重要な注意: このエラーは、MySQLのwait_timeoutが原因ではありません。そこに行って、それをやった。

この問題は、同時リクエストが同時に処理されたために発生したのではないかと思いました。私は自分を貧乏人の負荷テスターに​​しました:

for i in {1..10}; do (curl -o /dev/null http://domain.com &); done;

案の定、これらの10件のリクエスト内で、少なくとも1件は2006エラーをスローし、多くの場合はそれ以上になります。時々エラーはさらに奇妙なものになるでしょう、例えば:

sqlalchemy.exc.NoSuchColumnError: "Could not locate column in row for column 'table.id'"

列が最も確実に存在し、他のすべての同一のリクエストで正常に機能したとき。または、これ:

sqlalchemy.exc.ResourceClosedError: This result object does not return rows. It has been closed automatically.

もう一度、他のすべての要求に対してはうまくいきました。

問題が同時データベース接続に起因することをさらに確認するために、uWSGIをシングルワーカーに設定し、マルチスレッドを無効にして、リクエストを一度に1つずつ処理するように強制しました。案の定、問題は消えました。

問題を見つけるために、MySQLのエラーログを設定しました。MySQLの起動時のいくつかの通知を除いて、空のままです。

これが私のMySQL設定です:

[mysqld]
default-storage-engine = myisam
key_buffer = 1M
query_cache_size = 1M
query_cache_limit = 128k
max_connections=25
thread_cache=1
skip-innodb
query_cache_min_res_unit=0
tmp_table_size = 1M
max_heap_table_size = 1M
table_cache=256
concurrent_insert=2
max_allowed_packet = 1M
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 64K
innodb_file_per_table=1
log-error=/var/log/mysql/error.log

エラーの重いグーグルはほとんど明らかにしませんでしたが、max_allowed_pa​​cketを増やすよう提案しました。それを100Mに増やしてMySQLを再起動しましたが、まったく役に立ちませんでした。

まとめる と、MySQLへの同時接続が原因2006, 'MySQL server has gone away'で、その他の奇妙なエラーが発生します。MySQLのエラーログには関連性はありません。

私は何時間もこれに取り組んできましたが、何も進歩していません。誰かが私を助けてくれますか?


同時リクエストを処理しているとき、各スレッド(またはプロセスなど)はデータベースへの独自の接続を確立していますか?
DerfK

各プロセスには、SQLAlchemyによって管理される接続プールがあるため、各リクエストには独自の接続が必要です。
セロンルーン

もう1つの注意:負荷テストは私のローカル開発サーバーで問題を引き起こしません。サーバーのウェイトレスとデータベースのMySQLです。
セロンルーン

回答:


18

私もこれに遭遇し、理由と修正を見つけました。

これが発生する理由は、アプリケーションが親にロードされた後、python uwsgiプラグイン(またはより可能性が高いすべてのuwsgiプラグイン)が新しいワーカーをfork()するためです。その結果、子はすべてのリソース(db接続などのファイル記述子を含む)を親から継承します。

これについてはuwsgi wikiで簡単に読むことができます

uWSGIは、可能な限り、書き込み時にfork()コピーを悪用しようとします。デフォルトでは、アプリケーションをロードした後にフォークします。この動作を望まない場合は、-lazyオプションを使用してください。それを有効にすると、各ワーカーのfork()の後にアプリケーションをロードするようにuWSGIに指示します

そして、ご存じかもしれませんが、Pythonのmysqldb接続とカーソルは、明示的に保護しない限りスレッドセーフではありません。したがって、同じmysql接続/カーソルを同時に使用する複数のプロセス(uwsgiワーカーなど)は、それを破壊します。

私の場合(King Arthurのゴールド APIの場合)、別のモジュールのスコープでリクエストごとにMySQL接続を作成したときにこれはうまくいきましたが、パフォーマンスを向上させるために永続的な接続が必要なときは、データベース接続とカーソルをグローバルスコープに移動しました親モジュール。その結果、私のつながりはあなたのようにお互いを踏みつけていました。

これに対する修正は、uwsgi設定に "lazy"キーワード(または--lazyコマンドラインオプション)を追加することです。その結果、アプリケーションは、親からフォークして接続を共有するのではなく、子ごとに新たにフォークされます(そして、ある時点でそれを踏むと、MySQLサーバーは、ある時点での破損したリクエストが原因で強制的に閉じられます)。

最後に、uwsgi設定を変更せずにこれを行う方法が必要な場合は、@ postforkデコレーターを使用して、ワーカープロセスがフォークされた直後に新しいデータベース接続を適切に作成できます。あなたはそれについてここで読むことができます

あなたのフォローアップから、あなたはすでにpgsqlに切り替えたことがわかりますが、これが答えです。これにより、夜によく眠れるようになり、あなたのような人のために、私はこれに対する答えを見つけようとしています!

PS問題(ワーカーが互いに踏むためにカーソルが破損する)を理解していましたが、fork()と--lazyについて少し理解していなかったため、ワーカーが動作する場所に独自のプールを実装することを検討していました "グローバルスコープのプールからmysql接続をチェックアウトし、次にapplication()を終了する直前に「チェックイン」します。ただし、Web /アプリケーションの負荷が絶え間なく変化しない限り、-lazyを使用する方がはるかに適切です。新しいワーカーを作成します。それでも、独自のdb接続プールを実装するよりもはるかにクリーンであるため、-lazyを選択する場合があります。

編集:これに遭遇した他の人のためにそれに関する情報が不足しているので、この問題と解決策のより完全な記述があります:http ://tns.u13.net/?p=190


これを引き起こしている原因を知ることは間違いなく良いことです。ありがとうございました!
セロンルーン

この投稿が私が抱えていたのと同じ問題であり、あなたの解決策がそれを修正したことをそこに捨てただけです:)ありがとう!
MasterGberry 2014年

「そのため、同じmysql接続/カーソルを同時に使用する複数のプロセス(uwsgiワーカーなど)は、それを破壊します。」これは非常に有益でした。ローカルの同じデータベースへの2つの接続を開いて(1つはシェルから、もう1つはwsgiアプリケーションから)、このエラーが発生しました。データベースはそれ自体がping他のmysqladmin要求に対して生きていると報告していました。おそらく、シェルからデータベースを削除しようとしたためと思われますが、そのコマンドに対して「サーバーが削除されました」というエラーが表示され続けました。まあありがとう!
ブライアンピーターソン

あなたは私の命を救いました。
リーチ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.