Python WebサービスとクライアントWebサイトを並行して開発しています。クライアントからサービスへのHTTPリクエストを行うと、1回の呼び出しでsocket.pyでsocket.errorが常に発生します。 、読み取り中:
(104、「ピアによる接続のリセット」)
Wiresharkで聴くと、「良い」応答と「悪い」応答は非常に似ています。
Webサービスとクライアントの両方が、glibc-2.6.1を実行しているGentoo Linux x86-64ボックスで実行されています。同じvirtual_env内でPython 2.5.2を使用しています。
クライアントは、リクエストを行うためにhttplib2 0.4.0を呼び出しているDjango 1.0.2アプリです。OAuth署名アルゴリズム、 OAuthトークンは常に空の文字列に設定されます。
サービスは、Pythonのwsgiref.simple_serverを使用しているWerkzeug 0.3.1を実行しています。 WSGIアプリをwsgiref.validatorで問題なく実行しました。
これは簡単にデバッグできるように思えますが、サービス側で適切なリクエストをトレースすると、socket._socketobject.close()関数内の悪いリクエストのように見え、デリゲートメソッドをダミーメソッドに変換します。 sendまたはsendto(どちらを思い出せない)メソッドがオフに切り替えられると、FINまたはRSTが送信され、クライアントは処理を開始します。
「ピアによる接続のリセット」はサービスを非難しているようですが、httplib2も信用していません。クライアントに障害はありますか?
**さらにデバッグする-Linux上のサーバーのように見える**
MacBookを持っているので、一方でサービスを実行し、もう一方でクライアントWebサイトを実行してみました。 Linuxクライアントは、バグなしでOS Xサーバーを呼び出します(FIN ACK)。 OS Xクライアントは、バグ(RST ACK、および(54、「ピアによる接続リセット」))を使用してLinuxサービスを呼び出します。したがって、Linux上で実行されているサービスのように見えます。 x86_64ですか?悪いglibcですか? wsgiref?まだ見ている...
**さらなるテスト-wsgirefは不安定に見える**
Apacheとmod_wsgiを使用して本番環境に移行しましたが、接続のリセットはなくなりました。以下の回答を参照してください。ただし、接続のリセットを記録して再試行することをお勧めします。これにより、開発モードでサーバーを正常に実行し、実稼働で確実に実行できます。
この問題が発生しました。 Python「ピアによる接続リセット」問題 を参照してください。
(ほとんどの場合)Python Global Interpreter Lock。
time.sleep(0.01)
を戦略的に配置することで、これを(場合によっては)修正できます。
「どこ?」あなたが尋ねる。私を殴る。アイデアは、クライアント要求の内部および周辺で、より優れたスレッド同時実行性を提供することです。ただ置いてみてくださいbefore GILがリセットされ、Pythonインタープリターが保留中のスレッドをクリアできるようにリクエストを行います。
生産にはwsgirefを使用しないでください。 Apacheとmod_wsgiなどを使用します。
Wsgiref(werkzeugテストサーバー、およびDjangoテストサーバーなど)が使用するバックエンド)を使用して、これらの接続のリセットが頻繁に表示されます。エラーをログに記録することで、ループで呼び出しを再試行し、10回の失敗後にあきらめますhttplib2は2回試行しますが、さらにいくつか必要になります。
Apacheとmod_wsgiを実行しているときに接続がリセットされることはありません。私は彼らが何を違うようにするのかわかりませんが(おそらく彼らは彼らを単に覆い隠します)、彼らは現れません。
地元の開発者コミュニティに助けを求めたとき、誰かがwsgirefで接続がリセットされ、本番サーバー上で消えてしまうことを確認しました。そこにはバグがありますが、見つけるのは難しいでしょう。
Pythonを使用していることに気付きましたが、このJavaの記事が役立つことがわかりました。
http://Java.Sun.com/javase/6/docs/technotes/guides/net/articles/connection_release.html
通常、長引かないクローズを実行するとRSTが得られます(つまり、データが送信およびACKされなかった場合はスタックによって破棄されます)、クローズを許可すると通常のFINが得られます残ります(つまり、クローズは送信中のデータがACKされるのを待ちます)。
おそらくあなたがする必要があるのは、ソケットをリンガーに設定して、ソケットで行われた非残留クローズと到着したACKの間の競合状態を取り除くことですか?
しかし、nginx + uwsgiバックエンドにpython-requestsクライアントポストを使用して非常に大きなファイルをアップロードすると、同じ問題が発生しました。
原因となったのは、バックエンドが、クライアントが送信しようとしていたものよりも小さいアップロードの最大ファイルサイズの上限を持っていることでした。
この制限は実際にはnginxによって課されたものであるため、エラーはuwsgiログに表示されませんでした。
Nginxの制限を引き上げると、エラーが削除されました。