Sto correndo Django dietro nginx usando FastCGI. Ho scoperto che in alcune delle risposte inviate al client, si sta verificando una corruzione casuale dei dati nel mezzo delle risposte (potrebbero essere circa duecento byte al centro).
A questo punto l'ho ridotto a essere un bug nel gestore FastCGI di nginx o nel gestore FastCGI di Django (cioè probabilmente un bug in flup), poiché questo problema non si verifica mai quando eseguo il server Django in modalità standalone (ie runserver
). Succede solo in modalità FastCGI.
Altre tendenze interessanti:
Tende ad accadere con risposte più ampie. Quando un client accede per la prima volta, viene inviato un gruppo di blocchi da 1 MB per sincronizzarli con il DB del server. Dopo quella prima sincronizzazione, le risposte sono molto più piccole (di solito pochi KB alla volta). La corruzione sembra sempre accadere su quei blocchi da 1 MB inviati all'inizio.
Accade più spesso quando il client è connesso al server tramite LAN (ovvero connessione a bassa latenza e larghezza di banda elevata). Questo mi fa pensare che ci sia una specie di condizione di razza in nginx o flup che è esacerbata da un aumento della velocità dei dati.
In questo momento, ho dovuto aggirare questo problema inserendo un digest SHA1 aggiuntivo nell'intestazione della risposta e facendo in modo che il client respingesse le risposte in cui l'intestazione non corrisponde al checksum del corpo, ma questa è una specie di soluzione orribile.
Qualcun altro ha sperimentato qualcosa del genere, o ha qualche suggerimento su come identificare se è flup o nginx che è in errore qui in modo da poter presentare un bug con il team appropriato?
Grazie in anticipo per qualsiasi aiuto.
Nota: ho anche pubblicato un bug simile in lighttpd + FastCGI + Django qualche tempo fa: /programming/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to -inaspettato ... anche se questa non è la stessa cosa (troncamento contro corruzione), sta iniziando a sembrare che il colpevole comune sia flup / Django piuttosto che il web server ..
Modifica: dovrei anche notare qual è il mio ambiente:
OSX 10.6.6 su Mac Mini
Python 2.6.1 (Sistema)
Django 1.3 (dal tarball ufficiale)
flup 1.0.2 (dall'uovo di Python sul sito di flup)
nginx + ssl 1.0.0 (da Macports)
EDIT: in risposta al commento di Jerzyk, il percorso del codice che assembla la risposta appare come (modificato per succinto):
# 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
Non credo sia possibile che la lunghezza del contenuto sia errata in base a ciò, e AFAIK non ha modo di contrassegnare un oggetto Django HttpResponse in modo esplicito binario rispetto al testo. Inoltre, poiché il problema si verifica solo in modo intermittente, non penso che lo spieghi altrimenti presumibilmente lo vedresti su ogni richiesta.
EDIT @ionelmc: Devi impostare Content-Length in Django - nginx non lo imposta per te, come nell'esempio seguente una volta disabilitato l'impostazione Content-Length esplicitamente:
$ 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