Rails + thin: 无法下载大文件

Rails + thin: Not possible to download large files

我有一个 rails 应用程序,用户可以在其中管理大文件(目前最大 15 GB)。他们还可以下载存储的文件。

对于小于 510 MB 的文件,一切都完美无缺。但对于大于 510 MB 的文件,下载会在 522,256 KB (510 MB) 后停止。

我认为 thin 产生了这个问题。当我使用 thin 启动我的开发服务器时,我无法下载完整的文件。当我使用 webrick 启动开发服务器时,一切正常。

我使用 top 来比较 RAM/CPU 的行为,但是服务器 thin 和 webrick 的行为方式相同。在开发中,两个服务器都将完整的文件读取到 RAM 中,然后将其发送到 user/client.

我尝试更改 send_file 的一些选项,例如 streambuffer_size。我还手动设置了 length。但是同样,我无法使用 thin 下载完整文件。

我可以使用 Firefox、Chrome 和 curl 重现此行为。

问题是我的高效 rails 应用程序在 nginx 代理后面使用了 4 个瘦服务器。目前,我无法使用 unicorn 或 passenger。

在开发中,我使用thin 1.6.3rails 4.1.8ruby 2.1.2

下载
  file_path = '/tmp/big_file.tar.gz' # 5 GB
  send_file(file_path, buffer_size: 4096, 流: 真)
结尾

如果您使用的是 send_file,最好使用前端代理来转嫁提供文件的责任。你说你在生产中使用 nginx,所以:

在您的 production.rb 文件中,取消注释 config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

您还必须更改 nginx 配置以适应 Rack::Sendfile。它的文档位于 here。更改相当于添加:

proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping /=/files/; # or something similar that doesn't interfere with your routes

到您现有的位置块,并添加一个额外的 location 块来处理您添加的 X-Accel-Mapping。新位置块可能如下所示:

location ~ /files(.*) {
  internal;             
  alias ;             
}   

当您通过 ssh 连接到生产服务器和 curl -I 瘦服务器(not nginx)并看到 X-Accel-Redirect header。 curl(没有-I)直接到thin服务器应该发送文件内容。

你可以看到我最近与nginx和send_filehere的斗争。