39

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 を実行しています。問題なく wsgiref.validator を介して WSGI アプリを実行しました。

これは簡単にデバッグできるように思えますが、サービス側で適切なリクエストを追跡すると、socket._socketobject.close() 関数でデリゲート メソッドをダミー メソッドに変えて、不適切なリクエストのように見えます。send または sendto (どちらかは覚えていません) メソッドがオフになると、FIN または RST が送信され、クライアントは処理を開始します。

「ピアによる接続のリセット」はサービスに責任があるようですが、httplib2も信頼していません。クライアントに過失がある可能性はありますか?

** さらなるデバッグ - Linux 上のサーバーのように見えます **

私は MacBook を持っているので、1 台でサービスを実行し、もう 1 台でクライアント Web サイトを実行してみました。Linux クライアントは、バグ (FIN ACK) なしで OS X サーバーを呼び出します。OS X クライアントはバグ (RST ACK、および (54、「ピアによる接続のリセット」)) を使用して Linux サービスを呼び出します。つまり、Linuxで実行されているサービスのようです。x86_64ですか?悪いglibc?wsgiref? まだ見て...

** さらなるテスト - wsgiref は不安定に見える **

Apache と mod_wsgi を使用して本番環境に移行し、接続のリセットはなくなりました。以下の私の回答を参照してください。ただし、接続のリセットをログに記録して再試行することをお勧めします。これにより、サーバーは開発モードで問題なく動作し、本番環境でも安定して動作します.

4

4 に答える 4

27

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

(おそらく) Python Global Interpreter Lock に基づく小さなタイミングの問題に遭遇しました。

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

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

于 2008-12-20T22:18:15.750 に答える
11

wsgirefを本番環境に使用しないでください。Apacheとmod_wsgi、または他のものを使用してください。

これらの接続は、wsgiref(werkzeugテストサーバー、および場合によってはDjangoテストサーバーなどの他のサーバーで使用されるバックエンド)で頻繁にリセットされます。私たちの解決策は、エラーをログに記録し、ループで呼び出しを再試行し、10回失敗した後にあきらめることでした。httplib2は2回試行しますが、さらにいくつか必要でした。それらも束になっているようです-1秒の睡眠を追加すると問題が解決する可能性があります。

Apacheとmod_wsgiを実行しているときに、接続がリセットされるのを見たことがありません。彼らがどう違うのかはわかりませんが(たぶん彼らは彼らを覆い隠しているだけかもしれません)、彼らは現れません。

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

于 2009-01-27T00:37:29.857 に答える
3

通常、長続きしないクローズを行うと RST が返されます (つまり、データが送信されずに ACK が返されなかった場合、スタックによってデータが破棄される可能性があります)。クローズを許可すると、通常の FIN が返されます。残ります (つまり、クローズは転送中のデータが ACK されるのを待ちます)。

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

于 2008-12-21T12:44:18.997 に答える