设为首页 - 加入收藏 - 网站地图 欢迎加QQ群 :14364084
当前位置:谭博的博客 > web服务器 > nginx > 正文

nginx+fastcgi文件下载不全的解决方法

时间:2014-08-25 11:59 来源:未知 标签: 作者:谭博 阅读:
 问题:nginx+fastcgi+php+某论坛程序的环境下,通过论坛上传的比较大(500KB)的文件下载后体积变小了。而较小的文件(100KB)则安然无恙。
 
    用WinHex比较,可以看到文件从中间被截断了,并且没有多出任何内容。使用经多次测试,每次下载的大小在64KB左右(小于64KB),但不相 同。下载到64KB左右的时候卡住了,几秒钟之后下载进度直接跳到100%,显示下载完成。为排除伟大的墙的因素,翻 墙测试,每次下载的大小在127KB左右。
 
    找到论坛源代码,可以看到使用的是php的readfile()进行文件输出,而在输出前已经写入了content-length header。通过HttpFox进行观察,content-length的大小是正确的文件大小。
 
    由于64KB这个大小比较敏感,所以去代码里找了有没有循环缓存读取文件的地方,并没有发现。readfile()直接读取全部内容进行输出。
   为了排查,先将服务器切换到httpd(mod_php),则恢复正常,也就是说问题很可能在nginx和fastcgi上。
   检查nginx.conf,注意到这个地方:
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
 
    它的值正好等于64K,也就是说问题可能和它有关。将其修改为16K,重启nginx服务,重新下载,这次文件的大小变成了16KB左右。
    检查日志发现这么一行:
    2010/07/15 02:11:40 [crit] 6064#0: *112 open() "/var/lib/nginx/tmp/fastcgi/1/00/0000000001" failed (13: Permission denied)
 
    nginx会使用fastcgi_buffer_size指定的大小的缓冲区用于缓存fastcgi流的内容。当大小超出此大小时会继续用fastcgi_buffers指定的数量和大小申请缓冲区。如果依然超出此大小,会将多出的内容写入临时文件。
 
    也就是说,在本情况下,nginx首先会使用一个64K的缓冲区缓冲fastcgi流的第一部分,超出后最多申请4*64K=256K的缓冲区用于缓冲。如果继续超出,则写入临时文件。
    下载100KB的文件时,内存完全足够,不用写入临时文件,所以没有问题。
    下载500KB的文件,64KB+64KB*4已经装不下这个文件,需要使用临时文件。
 
     而日志中反应的就是nginx无权写入临时文件。我不清楚nginx在这里具体是如何实现的,个人猜测可能在写入失败后就放弃了后面4个缓冲区,发 送完第一个缓冲区后就停止发送。如果是这样,一旦超过keep-alive的时间,服务器会断开tcp连接,浏览器认为文件下载完成。考虑header的 大小,浏览器下载的文件略小于64KB。这样一来就能够解释通观察到的现象。
 
    将目录/var/lib/nginx/tmp权限改为可写后,问题解决。

 

关注微信公众号

微信扫一扫,打赏我

热评文章
    内容不错,支持一下
    评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)