nginx + fastCGI + Django-在发送给客户端的响应中出现数据损坏


10

我正在使用FastCGI在nginx后面运行Django。我发现在发送给客户端的某些响应中,响应的中间发生了随机数据损坏(中间可能有数百个字节左右)。

在这一点上,我将其范围缩小为Nginx的FastCGI处理程序或Django的FastCGI处理程序中的错误(即,可能是flup中的错误),因为当我在独立(即runserver)模式下运行Django服务器时,永远不会发生此问题。它仅在FastCGI模式下发生。

其他有趣的趋势:

  • 它倾向于在较大的响应上发生。客户端首次登录时,将向他们发送一堆1MB的块,以将其同步到服务器DB。第一次同步后,响应要小得多(通常一次只有几个KB)。损坏似乎总是发生在开始时发送的那些1MB数据块上。

  • 当客户端通过LAN连接到服务器时(即低延迟,高带宽连接),这种情况会更经常发生。这使我认为Nginx或flup中存在某种竞争状况,而这种竞争状况会由于数据速率的提高而加剧。

现在,我不得不通过在响应头中放置一个额外的SHA1摘要来解决此问题,并让客户端拒绝响应头与主体校验和不匹配的响应,但这是一种可怕的解决方案。

是否有其他人经历过类似的事情,或者是否有任何指示如何确定是flup还是nginx在这里出了问题,所以我可以向相应的团队提交错误报告?

在此先感谢您的帮助。

注:我也张贴了类似的错误在lighttpd的FastCGI的+ + Django的一段时间回到这里:/programming/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to -意想不到的 ...即使这不是同一件事(截断还是损坏),它也开始看起来是罪魁祸首是flup / Django而不是Web服务器。

编辑:我还应该注意我的环境是:

  • 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对象标记为显式二进制而不是文本。另外,由于该问题只是间歇性发生,因此我认为这不能解释该问题,否则您可能会在每次请求时看到它。

编辑@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 2010年

我可以想到两个可能的原因:错误的编码-HttpRespose作为文本与二进制还是错误的标头(尤其是内容长度)
Jerzyk 2011年

1
@glenc此响应的内容类型是什么?如果这是二进制文件-您可以尝试设置它吗?(例如mimetype ='application / x-ms-excel'或其他)
Jerzyk 2011年

2
如果您的传输编码已分块,则无需设置内容长度。rfc 2616明确禁止这样做:“如果这两个长度不同(即,如果存在Transfer-Encoding头字段),则不得发送Content-Length头字段。”
ionelmc 2011年

Answers:


1

对于fastcgi响应,您是否有任何活动的nginx缓存指令(bypass / no_cache)有效?

在nginx的1.0.3 Changenote中,他们修复了响应损坏:

错误修正:如果“ proxy / fastcgi / scgi / uwsgi_cache_bypass”和“ proxy / fastcgi / scgi / uwsgi_no_cache”指令值不同,则缓存的响应可能会中断;该错误已在0.8.46中出现。

资料来源:http : //nginx.org/en/CHANGES(1.0.3。section)


0

也许只有在输出包含至少一个UTF-8字符时才会发生偶尔的损坏。

内容长度和字符串长度不是一回事,因为一个UTF-8字符可以包含2到5个字节。


嗯..虽然这是事实,但似乎不太可能是原因,因为损坏发生在数据块的中间,而不仅仅是结尾丢失数据的情况。
glenc 2011年

0

解决这种情况的一种方法是:

  • 使nginx和django在不同的硬件上运行(以便您可以轻松捕获流量)
  • 捕获从客户端到-/-> nginx和nginx-/-> django的流量(即使用wireshark)

一旦在客户端(基于sha1)检测到错误,请转到网络捕获,查看记录的(TCP)流,并尝试查找问题是由nginx产生还是由django直接产生。


0

我有一个非常类似的问题,只要安装了此程序,它就会困扰我。像您一样,我使用FastCGI,Nginx和macOS,并发现在大请求中间出现随机损坏(大约占1.5 MB文档请求的2%)。

我能够通过在TCP-FPM(以我为例)和Nginx之间的FastCGI连接上通过TCP切换到Unix套接字来解决我的问题。我不知道是哪一部分难题导致了损坏,但是避免内部TCP连接确实可以解决该问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.