nginx + fastCGI + Django - obtendo corrupção de dados nas respostas enviadas ao cliente

9

Estou executando o Django por trás do nginx usando o FastCGI. Descobri que, em algumas das respostas enviadas ao cliente, ocorre uma corrupção aleatória de dados no meio das respostas (pode ser de algumas centenas de bytes no meio).

Neste ponto, reduzi-o a ser um bug no manipulador FastCGI do nginx ou no manipulador FastCGI do Django (isto é, provavelmente um bug no flup), já que esse problema nunca ocorre quando eu executo o servidor Django em independente (ou seja, runserver ). Acontece apenas no modo FastCGI.

Outras tendências interessantes:

  • Isso tende a acontecer em respostas maiores. Quando um cliente faz o login pela primeira vez, eles recebem um monte de blocos de 1 MB para sincronizá-los no banco de dados do servidor. Depois dessa primeira sincronização, as respostas são muito menores (geralmente alguns KB por vez). A corrupção parece sempre acontecer naqueles pedaços de 1MB enviados no início.

  • Acontece com mais frequência quando o cliente está conectado ao servidor via LAN (por exemplo, conexão de baixa latência e alta largura de banda). Isso me faz pensar que há algum tipo de condição de corrida no nginx ou flup que é exacerbada por um aumento na taxa de dados.

Neste momento, tive que contornar isso colocando um resumo SHA1 extra no cabeçalho de resposta e fazendo com que o cliente rejeitasse respostas em que o cabeçalho não correspondia à soma de verificação do corpo, mas essa é uma solução horrível .

Alguém mais experimentou algo assim, ou tem alguma indicação sobre como identificar se é flup ou nginx que está com defeito aqui, para que eu possa registrar um bug com a equipe apropriada?

Agradecemos antecipadamente por qualquer ajuda.

Nota: Eu também postei um bug similar no lighttpd + FastCGI + Django um tempo atrás: link ... mesmo que isso não seja a mesma coisa (truncation vs corruption), ele está começando a parecer que o culpado comum é flup / Django ao invés do servidor web ..

Editar: também devo observar o que é meu ambiente:

  • OSX 10.6.6 em um Mac Mini

  • Python 2.6.1 (Sistema)

  • Django 1.3 (do tarball oficial)

  • flup 1.0.2 (do ovo Python no site flup)

  • nginx + ssl 1.0.0 (de Macports)

EDIT: Em resposta ao comentário de Jerzyk, o caminho do código que monta a resposta parece (editado para sucinto):

# 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

Eu não acho que é possível que o Content-Length esteja errado com base nisso, e o AFAIK não tem como marcar um objeto Django HttpResponse como explicitamente binário em oposição ao texto. Além disso, como o problema acontece apenas de forma intermitente, não acho que isso explique, caso contrário, presumivelmente, você o veria a cada solicitação.

EDIT @ionelmc: Você precisa definir o Content-Length no Django - o nginx não define isso para você, conforme o exemplo abaixo, uma vez que eu desativei explicitamente o Comprimento do Conteúdo:

$ 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
    
por glenc 22.10.2010 / 13:34

3 respostas

1

Você tem algum tipo de diretiva de cache nginx (bypass / no_cache) ativa para as respostas fastcgi?

Em nginx '1.0.3 Changenotes eles corrigiram uma corrupção de resposta:

Bugfix: a cached response may be broken if "proxy/fastcgi/scgi/ uwsgi_cache_bypass" and "proxy/fastcgi/scgi/uwsgi_no_cache" directive values were different; the bug had appeared in 0.8.46.

Fonte: link (seção 1.0.3.)

    
por 31.10.2011 / 15:52
0

Talvez a corrupção ocasional aconteça apenas se a saída contiver pelo menos um caractere UTF-8.

O comprimento do conteúdo e o tamanho da string não são a mesma coisa, porque um caractere UTF-8 pode conter de 2 a 5 bytes.

    
por 12.08.2011 / 13:32
0

Uma forma de resolver este caso um pouco mais seria:

  • tem o nginx e o django sendo executados em hardware diferente (para que você possa capturar o tráfego com facilidade)
  • capture o tráfego do cliente para - / - > nginx e nginx - / - > Django (ou seja, use wireshark)

Depois de detectar um erro no lado do cliente (baseado no sha1), vá para a captura de rede, examine o fluxo gravado (TCP) e tente descobrir se o problema é gerado pelo nginx ou se ele vem (diretamente ) do django.

    
por 13.07.2011 / 15:34