为什么使用CarrierWave和Fog从S3检索文件URL需要这么长时间?

时间:2013-07-30 15:07:56

标签: ruby-on-rails amazon-s3 carrierwave fog

我正在使用CarrierWave(0.9.0),Fog(1.14.0)和S3来存储用户头像。确定给定用户的头像URL似乎需要很长时间。随后的通话时间会大大缩短。

配置/初始化/ fog.rb

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
  }
  config.fog_directory = ENV['AWS_S3_BUCKET_AVATAR']
  config.fog_public = false
end

user.rb

mount_uploader :avatar, ImageUploader

控制台

irb(main):002:0> Benchmark.measure { user.avatar_url }
=>   0.500000   0.020000   0.520000 (  0.537884)

irb(main):003:0> Benchmark.measure { user.avatar_url }
=>   0.000000   0.000000   0.000000 (  0.001830)

irb(main):004:0> Benchmark.measure { user.avatar_url }
=>   0.000000   0.000000   0.000000 (  0.001454)

irb(main):005:0> Benchmark.measure { user.avatar_url }
=>   0.000000   0.000000   0.000000 (  0.000998)

New Relic报告有时user.avatar_url需要1秒钟。什么可能导致这么慢? There's a discussion on slow URL generation for public files,但我的头像不公开。


更新1:

在第一次调用之前明确要求Fog和CarrierWave没有区别,因为返回false,表明它们已经加载。

irb(main):002:0> require 'carrierwave'
=> false
irb(main):003:0> require 'fog'
=> false
irb(main):004:0> Benchmark.measure { user.avatar_url }
=>   0.510000   0.030000   0.540000 (  1.627774)

更新2:

这是上传者:

# encoding: utf-8

class ImageUploader < CarrierWave::Uploader::Base

  include CarrierWave::RMagick

  storage :fog

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :s_32 do
   process resize_to_fill: [32, 32]
  end

  version :s_40 do
   process resize_to_fill: [40, 40]
  end

  version :s_50 do
   process resize_to_fill: [50, 50]
  end

  version :s_115_120 do
   process resize_to_fill: [115, 120]
  end

  version :s_128 do
   process resize_to_fill: [128, 128]
  end

  def extension_white_list
    %w(jpg jpeg gif png)
  end

end

更新3:

user.avatar.url似乎没有什么区别:

irb(main):003:0> Benchmark.measure { user.avatar.url }
=>   0.500000   0.030000   0.530000 (  0.926975)

2 个答案:

答案 0 :(得分:4)

我认为雾的需要可能仍然存在问题(尽管现在不太明显)。由于雾中有很多不同的东西,我们很久以前就做出了选择,推迟加载许多依赖项,直到它们被需要为止。这有利于加速“迷雾”,但在第一次发生某些事情时可能会减慢速度。我不确定我是如何忘记这一部分的,但是在我的机器上进行一些小的基准测试时,考虑到这一点,我肯定会看到速度减慢。

要解决此问题,您可以将上述相关要求基准更改为:

require 'benchmark'
require 'fog'
Fog::Storage.new(
  provider: 'AWS',
  aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
  aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
)
Benchmark.measure { ... }

您可能看起来有点奇怪,因为您没有使用该连接,但我将其设置为推迟加载S3细节,直到您这样做(例如,您不必加载S3细节)为了使用EC2)。但是,通过在某个较早的时间初始化连接,可以避免这种开销。希望这至少会让你更接近你想去的地方。

答案 1 :(得分:2)

我花了一些时间在这上面。虽然我没有找出根本原因,但这里有一些调查结果。你可以从我所做的开始,希望你不必太担心这个。

  • 根据你所说的和我的实验。只有在第一次调用 user.avatar_url 时才会出现这种缓慢。如果您在第一次通话后拨打 user.avatar_url another_user.avatar_url ,则会很快。基本上只有一个请求会受到这个“问题”的影响,所以我认为这不是一个大问题。
  • 第一次和后续通话有什么区别?我建议您使用ruby-prof来检查差异。我不是专家,但从报告中你会看到第一次运行比第二次运行加载更多东西。 ruby-prof提供了一些可能对您有帮助的报告,尤其是树形报告。

  • 我认为CarrierWave / Fog可能需要访问S3以确保url确实存在。通过使用不正确的S3存储桶排除了这一点。

以上报告由以下代码生成。

user = User.first
RubyProf.start
user.avatar_url
results = RubyProf.stop

File.open "/tmp/profile-graph1.txt", 'w' do |file|
  RubyProf::FlatPrinter.new(results).print(file)
end

RubyProf.start
user.avatar_url
results = RubyProf.stop

File.open "/tmp/profile-graph2.txt", 'w' do |file|
  RubyProf::FlatPrinter.new(results).print(file)
end