Estoy ejecutando Django detrás de nginx usando FastCGI. He descubierto que en algunas de las respuestas enviadas al cliente, se está produciendo corrupción aleatoria de datos en el medio de las respuestas (podría ser un par de cientos de bytes en el medio).
En este punto, lo he reducido a ser un error en el controlador FastCGI de nginx o en el controlador FastCGI de Django (es decir, probablemente un error en flup), ya que este problema nunca ocurre cuando ejecuto el servidor Django en modo independiente (es decir runserver
). Solo sucede en modo FastCGI.
Otras tendencias interesantes:
Tiende a suceder en respuestas más grandes. Cuando un cliente inicia sesión por primera vez, se le envían un montón de fragmentos de 1 MB para sincronizarlos con la base de datos del servidor. Después de esa primera sincronización, las respuestas son mucho más pequeñas (generalmente unos pocos KB a la vez). La corrupción siempre parece suceder en esos fragmentos de 1 MB enviados al inicio.
Ocurre más a menudo cuando el cliente está conectado al servidor a través de LAN (es decir, conexión de baja latencia y gran ancho de banda). Esto me hace pensar que hay algún tipo de condición de carrera en nginx o flup que se ve exacerbada por una mayor velocidad de datos.
En este momento, he tenido que solucionar esto poniendo un resumen SHA1 adicional en el encabezado de respuesta y haciendo que el cliente rechace las respuestas donde el encabezado no coincide con la suma de comprobación del cuerpo, pero esta es una solución horrible.
¿Alguien más ha experimentado algo como esto, o tiene alguna sugerencia sobre cómo identificar si es flup o nginx el que tiene la culpa aquí para que pueda presentar un error con el equipo apropiado?
Gracias de antemano por cualquier ayuda.
Nota: También publiqué un error similar en lighttpd + FastCGI + Django hace un tiempo aquí: /programming/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to inesperado ... a pesar de que esto no es lo mismo (truncamiento frente a corrupción), está empezando a parecer que el culpable común es flup / Django en lugar del servidor web ...
Editar: también debería tener en cuenta cuál es mi entorno:
OSX 10.6.6 en una Mac Mini
Python 2.6.1 (Sistema)
Django 1.3 (del tarball oficial)
flup 1.0.2 (desde Python egg en el sitio flup)
nginx + ssl 1.0.0 (de Macports)
EDITAR: en respuesta al comentario de Jerzyk, la ruta de código que ensambla la respuesta se ve (editada para ser sucinta):
# 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
No creo que sea posible que Content-Length sea incorrecto en función de eso, y AFAIK no hay forma de marcar un objeto Django HttpResponse como explícitamente binario en lugar de texto. Además, dado que el problema ocurre solo de manera intermitente, no creo que eso lo explique, de lo contrario, presumiblemente lo vería en cada solicitud.
EDITAR @ionelmc: debe configurar Content-Length en Django; nginx no lo configura para usted, según el ejemplo a continuación, una vez que desactivé la configuración de Content-Length explícitamente:
$ 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
fuente
Respuestas:
¿Tiene algún tipo de directiva nginx caching (bypass / no_cache) activa para las respuestas fastcgi?
En nginx '1.0.3 Changenotes arreglaron una respuesta de corrupción:
Fuente: http://nginx.org/en/CHANGES (sección 1.0.3.)
fuente
Quizás la corrupción ocasional solo ocurre si la salida contiene al menos un carácter UTF-8.
La longitud del contenido y la longitud de la cadena no son lo mismo, porque un carácter UTF-8 puede contener de 2 a 5 bytes.
fuente
Una forma de solucionar este caso un poco más sería:
Una vez que detecte un error en el lado del cliente (basado en el sha1), vaya a la captura de red, mire en la secuencia grabada (TCP) e intente averiguar si el problema es generado por nginx o proviene (directamente) de django .
fuente
Tuve un problema muy similar que me atormentaba durante el tiempo que tuve esta configuración. Al igual que usted, utilizo FastCGI, Nginx y macOS, y encontré corrupción aleatoria en medio de solicitudes grandes (era aproximadamente el 2% de las solicitudes de un documento de 1.5 MB).
Pude resolver mi problema al cambiar a sockets Unix sobre TCP para la conexión FastCGI entre PHP-FPM (en mi caso) y Nginx. No sé qué pieza del rompecabezas es responsable de la corrupción, pero evitar la conexión TCP interna lo solucionó.
fuente