nginx + fastCGI + Django-クライアントに送信された応答のデータ破損を取得


10

FastCGIを使用してnginxの背後でDjangoを実行しています。クライアントに送信された応答の一部で、ランダムなデータ破損が応答の途中で発生していることを発見しました(途中で数百バイト程度になる可能性があります)。

この時点で、私はそれをnginxのFastCGIハンドラーまたはDjangoのFastCGIハンドラーのバグ(つまり、おそらくflupのバグ)に絞り込みました。スタンドアロン(つまりrunserver)モードでDjangoサーバーを実行すると、この問題は発生しないためです。FastCGIモードでのみ発生します。

その他の興味深い傾向:

  • より大きな応答で発生する傾向があります。クライアントが初めてログインすると、1 MBのチャンクがサーバーDBに同期するために送信されます。最初の同期後、応答ははるかに小さくなります(通常、一度に数KB)。破損は常に、最初に送信された1MBのチャンクで発生しているようです。

  • これは、クライアントがLANを介してサーバーに接続されている場合(つまり、低遅延、高帯域幅接続)に頻繁に発生します。これにより、nginxまたはflupには、データレートの増加によって悪化するある種の競合状態があると思います。

現時点では、応答ヘッダーにSHA1ダイジェストを追加し、ヘッダーが本文のチェックサムと一致しない場合にクライアントに応答を拒否させることで、これを回避する必要がありましたが、これは恐ろしい解決策の一種です。

他の誰かがこのようなことを経験しましたか、または適切なチームにバグを報告できるように、ここで問題があるのがflupであるかnginxであるかを識別する方法に関する指針がありますか?

助けてくれてありがとう。

注:私も同様にlighttpd + FastCGI + Djangoに同様のバグを投稿しました:https : //stackoverflow.com/questions/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to -予期しない ...これは同じことではありませんが(切り捨てvs破損)、一般的な原因はWebサーバーではなくflup / Djangoであるように見え始めています。

編集:私の環境もメモする必要があります:

  • Mac Mini上のOSX 10.6.6

  • Python 2.6.1(システム)

  • Django 1.3(公式のtarballから)

  • flup 1.0.2(flupサイトのPython eggから)

  • nginx + ssl 1.0.0(Macportsから)

編集:Jerzykのコメントに応じて、応答を組み立てるコードパスは次のようになります(簡潔にするために編集されています)。

# This returns an objc NSData object, which is an array.array 
# when pushed through the PyObjC bridge
ret = handler( request ) 

response = HttpResponse( ret )
response[ "Content-Length" ] = len( ret )
return response

これに基づいてContent-Lengthが間違っている可能性はないと思います。AFAIKには、Django HttpResponseオブジェクトをテキストではなく明示的にバイナリとしてマークする方法はありません。また、この問題は断続的にしか発生しないため、それが原因であるとは考えられません。

EDIT @ionelmc:DjangoでContent-Lengthを設定する必要があります-次の例のように、明示的にContent-Lengthの設定を無効にすると、nginxはこれを設定しません。

$ curl -i http://localhost/io/ping
HTTP/1.1 200 OK
Server: nginx/1.0.0
Date: Thu, 23 Jun 2011 13:37:14 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive

AKSJDHAKLSJDHKLJAHSD

初期チャンクが頻繁に変更されない場合、またはユーザー固有でない場合は、ディスクに書き込み、nginxを介して直接提供する方が良い方法でしょうか?
sunn0

残念ながら、チャンクはユーザー固有であり、頻繁に変更されるため、この種のキャッシュはこのアプリケーションに適していません。私はまた、このデータ破損を単に回避するのではなく、実際に何がこのデータ破損を引き起こしているのかを知りたいと思っています(ヘッダーの追加のSHA1ダイジェストで既に行っています)。
glenc

私は2つの考えられる理由を考えることができます:間違ったエンコード-バイナリとしてのHttpResposeと間違ったヘッダー(特にcontent-length)
Jerzyk

1
@glencこの応答のコンテンツタイプは何ですか?これがバイナリの場合-設定してみますか?(例:mimetype = 'application / x-ms-excel'またはそれ以外)
Jerzyk

2
Transfer-Encodingがチャンク化されている場合は、content-lengthを設定する必要はありません。rfc 2616はこれを明示的に禁止します。「これら2つの長さが異なる場合(つまり、Transfer-Encodingヘッダーフィールドが存在する場合)、Content-Lengthヘッダーフィールドを送信してはなりません(MUST NOT)。」
ionelmc

回答:


1

fastcgi応答に対してアクティブなnginxキャッシング(bypass / no_cache)ディレクティブはありますか?

nginxの1.0.3 Changenotesでは、応答の破損を修正しました。

バグ修正:「proxy / fastcgi / scgi / uwsgi_cache_bypass」と「proxy / fastcgi / scgi / uwsgi_no_cache」ディレクティブの値が異なる場合、キャッシュされた応答が壊れる可能性があります。このバグは0.8.46で発生しました。

出典:http : //nginx.org/en/CHANGES(1.0.3。セクション)


0

おそらく、出力に少なくとも1つのUTF-8文字が含まれている場合にのみ、偶発的な破損が発生する可能性があります。

1つのUTF-8文字には2〜5バイトを含めることができるため、コンテンツの長さと文字列の長さは同じではありません。


うーん..これは本当ですが、データチャンクの途中で破損が発生していて、最後にデータが欠落しているだけのケースではなかったため、原因であるとは思われません。
glenc

0

このケースをもう少しトラブルシューティングする1つの方法は、次のとおりです。

  • nginxとdjangoを異なるハードウェアで実行する(トラフィックを簡単にキャプチャできるようにするため)
  • クライアントから-/-> nginxおよびnginxへのトラフィックをキャプチャします-/-> django(つまり、wiresharkを使用)

(sha1に基づいて)クライアント側でエラーを検出したら、ネットワークキャプチャに移動し、記録された(TCP)ストリームを調べて、問題がnginxによって生成されたものか、djangoから(直接)発生したものかを見つけます。 。


0

私が持っていた非常に同様の問題として長い間、私は、このセットアップを持っていたとして、私を悩ませました。あなたと同じように、私はFastCGI、Nginx、およびmacOSを使用しており、大きなリクエストの途中でランダムな破損を発見しました(1.5 MBドキュメントのリクエストの約2%でした)。

PHP-FPM(私の場合)とNginx間のFastCGI接続をTCP経由でUnixソケットに切り替えることで問題を解決できました。パズルのどの部分が破損の原因であるかはわかりませんが、内部TCP接続を回避することで解決しました。

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