web-dev-qa-db-ja.com

104、「ピアによって接続がリセットされました」ソケットエラー、またはソケットを閉じるとFINではなくRSTになるのはいつですか?

Python WebサービスとクライアントWebサイトを並行して開発しています。クライアントからサービスへのHTTPリクエストを行うと、1回の呼び出しでsocket.pyでsocket.errorが常に発生します。 、読み取り中:

(104、「ピアによる接続のリセット」)

Wiresharkで聴くと、「良い」応答と「悪い」応答は非常に似ています。

  • OAuthヘッダーのサイズのため、要求は2つのパケットに分割されます。サービスはACKで両方に応答します
  • サービスは、ヘッダーごとに1パケット(HTTP/1.0 200 OK、次にDateヘッダーなど)の応答を送信します。クライアントはそれぞれにACKで応答します。
  • (良好な要求)サーバーはFIN、ACKを送信します。クライアントはFIN、ACKで応答します。サーバーはACKに応答します。
  • (悪い要求)サーバーはRST、ACKを送信し、クライアントはTCP応答を送信しません。クライアント側でsocket.errorが発生します。

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を使用して本番環境に移行しましたが、接続のリセットはなくなりました。以下の回答を参照してください。ただし、接続のリセットを記録して再試行することをお勧めします。これにより、開発モードでサーバーを正常に実行し、実稼働で確実に実行できます。

30
jwhitlock

この問題が発生しました。 Python「ピアによる接続リセット」問題 を参照してください。

(ほとんどの場合)Python Global Interpreter Lock。

time.sleep(0.01)を戦略的に配置することで、これを(場合によっては)修正できます。

「どこ?」あなたが尋ねる。私を殴る。アイデアは、クライアント要求の内部および周辺で、より優れたスレッド同時実行性を提供することです。ただ置いてみてくださいbefore GILがリセットされ、Pythonインタープリターが保留中のスレッドをクリアできるようにリクエストを行います。

21
S.Lott

生産にはwsgirefを使用しないでください。 Apacheとmod_wsgiなどを使用します。

Wsgiref(werkzeugテストサーバー、およびDjangoテストサーバーなど)が使用するバックエンド)を使用して、これらの接続のリセットが頻繁に表示されます。エラーをログに記録することで、ループで呼び出しを再試行し、10回の失敗後にあきらめますhttplib2は2回試行しますが、さらにいくつか必要になります。

Apacheとmod_wsgiを実行しているときに接続がリセットされることはありません。私は彼らが何を違うようにするのかわかりませんが(おそらく彼らは彼らを単に覆い隠します)、彼らは現れません。

地元の開発者コミュニティに助けを求めたとき、誰かがwsgirefで接続がリセットされ、本番サーバー上で消えてしまうことを確認しました。そこにはバグがありますが、見つけるのは難しいでしょう。

11
jwhitlock

Pythonを使用していることに気付きましたが、このJavaの記事が役立つことがわかりました。

http://Java.Sun.com/javase/6/docs/technotes/guides/net/articles/connection_release.html

5
Sean McCauliff

通常、長引かないクローズを実行するとRSTが得られます(つまり、データが送信およびACKされなかった場合はスタックによって破棄されます)、クローズを許可すると通常のFINが得られます残ります(つまり、クローズは送信中のデータがACKされるのを待ちます)。

おそらくあなたがする必要があるのは、ソケットをリンガーに設定して、ソケットで行われた非残留クローズと到着したACKの間の競合状態を取り除くことですか?

2
Len Holgate

しかし、nginx + uwsgiバックエンドにpython-requestsクライアントポストを使用して非常に大きなファイルをアップロードすると、同じ問題が発生しました。

原因となったのは、バックエンドが、クライアントが送信しようとしていたものよりも小さいアップロードの最大ファイルサイズの上限を持っていることでした。

この制限は実際にはnginxによって課されたものであるため、エラーはuwsgiログに表示されませんでした。

Nginxの制限を引き上げると、エラーが削除されました。

1
David Simic