Nginx反向代理导致文件下载需要花费过多时间才能启动

概观

我的networking应用程序允许用户通过我的服务器上传存储在s3上的文件。 当用户请求文件时,我的Web服务器从s3中检索它,然后将其发送到客户端。

我最近部署了一个负载均衡器,使我目前的设置如下:

Web应用服务器设置

注意目前我只有一个Web服务器来简化debugging。

初始问题

部署负载平衡器后,我发现大型文件(大于4MB左右)的下载会在60秒后504网关超时失败。

我查看了网站的负载均衡器nginx错误日志,我看到了一些条目,如:

[error] 11770#11770: *40 upstream timed out (110: Connection timed out) while reading response header from upstream, client: XXXX, ... 

当我看到网站服务器nginx错误日志为网站,我看到了类似的条目:

 [error] 6632#6632: *41 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ... [error] 6632#6632: *85 upstream timed out (110: Connection timed out) while reading response header from upstream, client: ... [error] 7163#7163: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ... [error] 7505#7505: *41 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: ... [error] 7505#7505: *91 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: .... 

看看我的Web服务器上的php-fpm错误日志:

 WARNING: [pool www] child 3011, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (64.950545 sec), terminating WARNING: [pool www] child 3011 exited on signal 15 (SIGTERM) after 1140.059968 seconds from start WARNING: [pool www] server reached pm.max_children setting (5), consider raising it WARNING: [pool www] child 4260, script '/home/forge/XXX.com/public/index.php' (request: "GET /index.php") execution timed out (68.171099 sec), terminating WARNING: [pool www] child 4260 exited on signal 15 (SIGTERM) after 160.005837 seconds from start NOTICE: [pool www] child 4271 started 

我把这个放在没有我的PHP执行超时和nginx连接超时太低,所以我增加了他们做了以下几点:

  • 在负载平衡器上:
    • 添加proxy_read_timeout 600s; 到/etc/nginx/nginx.conf
  • 在Web服务器上:
    • 在nginx站点configuration我加了fastcgi_read_timeout 600; 到.php位置块。
    • 在php-fpmconfiguration中添加了max_execution_time = 600default_socket_timeout = 600
    • 向/etc/php/7.0/fpm/pool.d/www.conf添加了request_terminate_timeout = 300

这固定我最初的问题,因为我现在可以下载更大的文件(testing高达25 MB)。

下一个问题 – 下载缓慢

上面的configuration更改后,我可以无超时下载文件,但下载开始需要大量时间(〜300秒),实际下载本身很慢(小问题)。

下载文件的stream程如下:

  • 客户端点击命中我的服务器的uri链接
  • 我的Web服务器转到数据库并获取信息,如散列文件名和数据库服务器的path。
  • Web服务器然后从S3中检索文件。
  • Web服务器将该文件作为初始请求的下载进行响应:

为了参考,在Web服务器上运行的function是:

 public function show($projectID, $documentID, $revisionID, $fileID) { $fileEntry = File::find($fileID); $path = $fileEntry->path(); $file = Storage::get($path); $size = Storage::size($path); return Response::make($file, 200) ->header('Content-Type', $fileEntry->mime) ->header('Content-Disposition', 'attachment; filename="' . $fileEntry->original_filename . '"') ->header('Content-Length:', $size); } 

我明白,我是双重处理文件,并在未来将切换到签名s3 urlredirect,但也有其他部分的应用程序,这将是不实际的(抓住文件的集合,压缩和发送到客户端),因此将喜欢获得一些理解。

这个问题的原因是什么? 我不相信在部署负载均衡器之前我曾遇到过这个问题。

如果我从s3直接下载文件,下载时间是通过我的服务器来的整体时间的一小部分,所以我不认为双重处理是问题。 可能是缓冲区或内存大小相关?

附加信息:

  • Laravel伪造曾用于configuration和服务器。
  • 负载均衡器上的SSL终止
  • Laravelnetworking应用程序
  • Linode的全部都在新加坡数据中心托pipe
  • S3地区是悉尼
  • 问题发生在极低的stream量(低至1个客户端)

很好的编辑,事情更清晰。

这似乎是在PHP中的应用程序超时。 我最好的猜测是,PHP完全将大文件下载到临时位置,然后将其返回,而不是直接将其返回。 这就解释了延迟,尽pipe速度不是很慢。 我甚至不知道是否直接从S3中获得直接stream媒体,如果需要的话(通过你)进行研究。 我也看到如果PHP5有所作为,我发现PHP7在一些边缘情况下可靠性较低。

我会跟踪请求进来时的确切时间,击中每个服务器,并且每个服务器返回响应,以便您可以完全跟踪请求。 这在PHP层尤其如此,当应用程序服务器接收到请求时,添加日志logging,从S3中获取请求时,以及何时开始将其发送回客户端。

下载速度有点令人费解。 我会find一种方法来testing您的PHP服务器和S3之间的速度 – 做一个curl或什么 – 可能是一个简单的带宽问题,或延迟减less带宽可用。 解决方法可能是使用CloudFront,但可能不会,因为这只会在第二次请求时加速下载,而不是第一次。

一旦你完成了所有这一切,如果你还没有发布你发现的信息 – 特别是几个请求击中每一层的确切时间,以及返回响应的时间。