使用aws-sdk-ruby时,Aws :: S3 put_object非常慢

时间:2018-02-22 14:50:00

标签: ruby-on-rails amazon-s3 aws-sdk

我们在Heroku上托管的Rails应用程序上的后台工作程序上生成PDF文件,一旦生成它们就会上传到Amazon S3。 Heroku app和S3 bucket都位于eu-west-1区域。

我们正在经历慢速上传,非常基本的小文件。看看这个例子:

Aws.config.update({
  region: 'eu-west-1',
  credentials: Aws::Credentials.new(ENV['S3_USER_KEY'], ENV['S3_USER_SECRET'])
})

S3_BUCKET = Aws::S3::Resource.new.bucket(ENV['S3_PRIVATE_BUCKET'])

file = Tempfile.new(["testfile", ".pdf"], encoding: "ascii-8bit").tap do |file|
  file.write("a"*5000)
end

Benchmark.bm do |x|
  x.report { S3_BUCKET.put_object(key: "testfile.pdf", body: file) }
end

   user       system     total      real
   0.020000   0.040000   0.060000   ( 40.499553)

我想我不能做一个更简单的例子,所以发送一个包含5000个字符的文件需要40秒才能从Heroku一次性实例上传到S3。

请注意,我在我的(国内)互联网连接和Heroku实例上进行了测试,结果几乎相似。 另一方面,我使用ForkLift.app作为GUI浏览我的存储桶,上传文件几乎是即时的。

我一直在浏览aws-sdk文档,但我无法解释如何解释这么慢的上传

3 个答案:

答案 0 :(得分:1)

put_object和TempFile似乎有问题

尝试先将文件传递给IO

new_file = IO.read(file)
S3_BUCKET.put_object(key: "testfile.pdf", body: new_file)

答案 1 :(得分:0)

似乎AwsSdk是罪魁祸首。 我用其他方式测试了上传相同的文件:

使用Aws CLI

(我使用的是手机连接,因此网络非常慢,我没有花时间在Heroku Dyno上安装/配置aws CLI)

Benchmark.bm do |x|
  x.report { `aws s3 cp #{file.path} s3://#{ ENV['S3_BUCKET']}/testfile.pdf` }
end

0.000000   0.000000   0.510000 (  2.486112)

使用Fog AWS

这是从Heroku Dyno开始的。

connection = Fog::Storage.new({
  :provider                 => 'AWS',
  :aws_access_key_id        => ENV['S3_USER_KEY'],
  :aws_secret_access_key    => ENV['S3_USER_SECRET'],
  region: "eu-west-1"
})

directory = connection.directories.new(key: ENV["S3_BUCKET"], region: "eu-west-1")

Benchmark.bmb do |x|
  x.report do
    directory.files.create(
      :key    => 'test-with-fog.pdf',
      :body   => file,
    )
  end
end

       user     system      total        real
   0.010000   0.010000   0.020000 (  0.050712)

我会坚持最新的解决方法。尽管如此,我还没有找到导致aws-sdk这么慢的原因。

答案 2 :(得分:0)

在创建Aws::S3::Object并使用方法upload_file时遇到了类似的问题。如果我传递了TempFile对象,那么即使上传一个小文件(〜5KB)也要花费约40秒。但是,传递TempFile.path的速度惊人地快(不到1秒)。

您可能出于自己的原因需要使用AWS::S3::Bucket方法put_object,但是put_object the image in the plot pane still do not have a titleStringIO,不是FileTempFile路径。如果您可以重构以创建AWS::S3::Object并使用upload_file,则可以使用此替代方法。

require 'aws-sdk-s3'

s3_resource = Aws::S3::Resource.new(region: 'us-east-2')

file = Tempfile.new(["testfile", ".pdf"], encoding: "ascii-8bit").tap do |file|
  file.write("a"*5000)
end

Benchmark.bm do |x|
  x.report {
    obj = s3_resource.bucket('mybucket').object("testfile-as-object.pdf")

    #passing the TempFile object is quite slow
    obj.upload_file(file)
  }
end

#       user     system      total        real
#   0.010359   0.006335   0.016694 ( 41.175544)

Benchmark.bm do |x|
  x.report {
    obj = s3_resource.bucket('mybucket').object("testfile-as-path.pdf")

    #passing the TempFile object's path is massively faster than passing the TempFile object itself
    obj.upload_file(file.path)
  }
end

#       user     system      total        real
#   0.004573   0.002032   0.006605 (  0.398605)