概述

概述

概述

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

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

Web 应用服务器设置

请注意,目前我只有一个网络服务器来简化调试。

初始问题

部署负载均衡器后,我注意到较大的文件(任何大于 4 MB 的文件)的下载会在 60 秒后失败,并出现 504 网关超时。

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

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

当我查看该网站的 Web 服务器 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 站点配置中我添加了fastcgi_read_timeout 600;.php 位置块。
    • 已添加max_execution_time = 600default_socket_timeout = 600至 php-fpm 配置。
    • 添加request_terminate_timeout = 300到 /etc/php/7.0/fpm/pool.d/www.conf

这在一定程度上解决了我最初的问题,因为我现在可以下载更大的文件(经测试最大可达 25 MB)。

下一个问题 - 下载速度慢

经过上述配置更改后,我可以无超时下载文件,但是下载开始需要过多的时间(约 300 秒)并且实际下载本身很慢(小问题)。

下载文件的流程如下:

  • 客户端点击 uri 链接到达我的服务器
  • 我的网络服务器进入数据库并获取数据库服务器的散列​​文件名和路径等信息。
  • 然后,Web 服务器从 S3 检索该文件。
  • Web 服务器将文件作为对初始请求的下载进行响应:

作为参考,在 Web 服务器上运行的执行此操作的函数是:

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 url 重定向,但在应用程序的其他部分,这并不切实际(抓取文件集合、压缩并发送到客户端),因此想获得一些了解。

这个问题可能是什么原因造成的?我认为在部署负载均衡器之前我从未遇到过这个问题。

如果我直接从 s3 下载文件,下载时间只是通过我的服务器下载总时间的一小部分,因此我认为问题不在于双重处理。这可能与缓冲区或内存大小有关吗?

附加信息:

  • Laravel forge 用于配置和服务器。
  • 负载均衡器上的 SSL 终止
  • Laravel Web 应用程序
  • Linode 全部托管在新加坡数据中心
  • S3 地区是悉尼
  • 在流量极低时(降至 1 个客户端)观察到问题

答案1

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

这似乎是 PHP 中的应用程序超时。我最好的猜测是 PHP 完全将大文件下载到临时位置然后返回它们,而不是直接将它们流式传输回来。这解释了延迟,但不是导致速度缓慢的原因。我甚至不知道直接流式传输是否可行,直接从 S3 通过您的堆栈返回 - 如果需要(由您进行研究)。我还会看看 PHP5 是否有所作为,我发现 PHP7 在一些极端情况下不太可靠。

我会跟踪请求进入、到达每台服务器以及每台服务器返回响应的确切时间,以便您可以全面跟踪请求。这在 PHP 层尤其如此,添加应用服务器收到请求时、从 S3 获取请求时以及开始将其发送回客户端时记录。

下载速度有点令人费解。我会找到一种方法来测试您的 PHP 服务器和 S3 之间的速度 - 执行 curl 或类似操作 - 这可能是一个简单的带宽问题,或者延迟会降低可用带宽。一种解决方法可能是使用 CloudFront,但可能不行,因为这只会在第二次请求时加速下载,而不是第一次。

完成所有这些操作后,如果您还没有弄清楚,请发布您发现的信息 - 特别是一些请求到达每一层的确切时间,以及返回响应的时间。

相关内容