ruby-on-rails Aws::S3 put_object在aws-sdk-ruby下运行非常慢

qnzebej0  于 12个月前  发布在  Ruby
关注(0)|答案(5)|浏览(120)

我们在Heroku托管的Rails应用程序的后台工作人员上生成PDF文件,一旦生成,它们就会上传到Amazon S3。Heroku应用程序和S3存储桶都位于eu-west-1区域。
我们正在经历非常慢的上传,altghough非常基本的小文件。看看这个例子:

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文档,我看不到任何东西来解释这样一个缓慢的上传

monwx1rj

monwx1rj1#

好像是put_object和TempFile的问题
尝试先将文件传递给IO

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

字符串

ztigrdn8

ztigrdn82#

看来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运行缓慢的原因。

fwzugrvs

fwzugrvs3#

我在创建Aws::S3::Object并使用upload_file方法时遇到了类似的问题。如果我传入TempFile对象,即使上传一个小文件(~ 5 KB)也需要~40秒。然而,传入TempFile.path的速度快得惊人(不到1秒)。
您可能需要使用AWS::S3::Bucket方法put_object,但put_object似乎只接受StringIO,而不是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)

字符串

643ylb08

643ylb084#

我认为你在put_object中缺少了content_type。
S3_BUCKET.put_object(key:“testfile.pdf”,body:file,content_type:“application/pdf”
我有相同的测试性能与此,它会增加从20秒到2毫秒的PDF文件上传.
希望这对你有帮助。

myss37ts

myss37ts5#

我的解决方案:

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

# user       system     total      real
# 0.003022   0.000740   0.003762   (0.018425)

字符串

相关问题