我的networking应用程序允许用户通过我的服务器上传存储在s3上的文件。 当用户请求文件时,我的Web服务器从s3中检索它,然后将其发送到客户端。
我最近部署了一个负载均衡器,使我目前的设置如下:
注意目前我只有一个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 fastcgi_read_timeout 600; 到.php位置块。 max_execution_time = 600和default_socket_timeout = 600 。 request_terminate_timeout = 300 这固定我最初的问题,因为我现在可以下载更大的文件(testing高达25 MB)。
上面的configuration更改后,我可以无超时下载文件,但下载开始需要大量时间(〜300秒),实际下载本身很慢(小问题)。
下载文件的stream程如下:
为了参考,在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直接下载文件,下载时间是通过我的服务器来的整体时间的一小部分,所以我不认为双重处理是问题。 可能是缓冲区或内存大小相关?
附加信息:
很好的编辑,事情更清晰。
这似乎是在PHP中的应用程序超时。 我最好的猜测是,PHP完全将大文件下载到临时位置,然后将其返回,而不是直接将其返回。 这就解释了延迟,尽pipe速度不是很慢。 我甚至不知道是否直接从S3中获得直接stream媒体,如果需要的话(通过你)进行研究。 我也看到如果PHP5有所作为,我发现PHP7在一些边缘情况下可靠性较低。
我会跟踪请求进来时的确切时间,击中每个服务器,并且每个服务器返回响应,以便您可以完全跟踪请求。 这在PHP层尤其如此,当应用程序服务器接收到请求时,添加日志logging,从S3中获取请求时,以及何时开始将其发送回客户端。
下载速度有点令人费解。 我会find一种方法来testing您的PHP服务器和S3之间的速度 – 做一个curl或什么 – 可能是一个简单的带宽问题,或延迟减less带宽可用。 解决方法可能是使用CloudFront,但可能不会,因为这只会在第二次请求时加速下载,而不是第一次。
一旦你完成了所有这一切,如果你还没有发布你发现的信息 – 特别是几个请求击中每一层的确切时间,以及返回响应的时间。