回形针 Nginx 504 网关超时

Paperclip Nginx 504 Gateway Time-out

我有一个 Rails 4 应用程序,它允许使用 jQuery Dropzone 插件和回形针 gem 上传视频。每个上传的视频都被编码成多种格式,并在后台使用 delayed_paperclip、av-transcoder 和 sidekiq gems.

上传到 Amazon S3

大多数视频都可以正常工作,但在上传到达似乎是 dropzone 插件进度条的末尾后,它的大小更大,如 1.1GB returns Nginx 504 网关超时.

就服务器而言,rails 应用程序在负载均衡器后面的几台服务器上的 Nginx + Passenger 上运行(此处也使用 Nginx)。我没有在负载均衡器的上游部分设置超时,client_max_body_size 设置为 2000M(在负载均衡器和服务器上),我试过设置 passenger_pool_idle_time to a large value (600), that didn't help, I have also tried setting send_timeout (600s),没有有什么不同。

注意:进行这些更改时,我在两台服务器以及负载均衡器的主机文件上进行了更改,之后总是重新启动 nginx。

我也阅读了一些关于类似问题的答案,例如 this one and this one,但仍然无法弄清楚,google 也没有多大帮助。

一些不熟悉整个过程的额外说明paperclip/delayed_paperclip,文件上传到服务器,然后就用户而言,在后台完成操作post 视频处理(encoding/uploading 到 S3)作为作业推送到 Redis,Sidekiq 会在它有 time/resources.

时处理它

是什么导致了这个问题?我该如何调试并解决它?

更新

感谢 Sergey 的回答,我得以解决问题。由于我仅限于特定版本的 Paperclip,我无法将其更新到具有修复程序的最新版本,因此我将在此处保留我最终所做的事情。

在我用来处理上传的引擎中,我在 engine_name.rb 文件中添加了以下代码以覆盖 Paperclip 中需要修复的方法:

  Paperclip::AbstractAdapter.class_eval do
    def copy_to_tempfile(src)
      link_or_copy_file(src.path, destination.path)
      destination
    end

    def link_or_copy_file(src, dest)
      Paperclip.log("Trying to link #{src} to #{dest}")
      FileUtils.ln(src, dest, force: true) # overwrite existing
      @destination.close
      @destination.open.binmode
    rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT => e
      Paperclip.log("Link failed with #{e.message}; copying link #{src} to #{dest}")
      FileUtils.cp(src, dest)
    end
  end

  Paperclip::AttachmentAdapter.class_eval do
    def copy_to_tempfile(source)
      if source.staged?
        link_or_copy_file(source.staged_path(@style), destination.path)
      else
        source.copy_to_local_file(@style, destination.path)
      end
      destination
    end
  end

  Paperclip::Storage::Filesystem.class_eval do
    def flush_writes #:nodoc:
      @queued_for_write.each do |style_name, file|
        FileUtils.mkdir_p(File.dirname(path(style_name)))
        begin
          move_file(file.path, path(style_name))
        rescue SystemCallError
          File.open(path(style_name), "wb") do |new_file|
            while chunk = file.read(16 * 1024)
              new_file.write(chunk)
            end
          end
        end
        unless @options[:override_file_permissions] == false
          resolved_chmod = (@options[:override_file_permissions] &~ 0111) || (0666 &~ File.umask)
          FileUtils.chmod( resolved_chmod, path(style_name) )
        end
        file.rewind
      end

      after_flush_writes # allows attachment to clean up temp files

      @queued_for_write = {}
    end

    private

    def move_file(src, dest)
      # Support hardlinked files
      if File.identical?(src, dest)
        File.unlink(src)
      else
        FileUtils.mv(src, dest)
      end
    end

  end

我刚才遇到了类似的问题。也许,我的经验会有所帮助。

我们在 Amazon 上有 m3.medium 个实例,内存为 4Gb。 用户可以上传大型视频文件。我们在上传大于 400Mb 的文件时遇到 504 错误的问题。

在监控和记录上传过程期间,Paperclip 似乎为每个附件创建了 4 个文件,因此所有实例资源都在一个文件系统上工作。 这里有这个问题的描述

https://github.com/thoughtbot/paperclip/issues/1642

并提出了一个解决方案 - 尽可能使用 links 而不是文件。您可以在此处查看适当的代码更改

https://github.com/arnonhongklay/paperclip/commit/cd80661df18d7cd112944bfe26d90cb87c928aad

不过2天前Paperclip更新到5.2.0版本,他们实现了类似的解决方案。 所以现在它只为每个附件创建一个文件。因此我们的文件系统没有超载,更新到 5.2.0 版本后我们不再收到 504 错误。

结论:

  1. 如果您因某种原因在 Paperclip 版本中受到限制,请使用上面所附 link 中的猴子补丁
  2. 将Paperclip更新至5.2.0版本。应该有帮助