如何在Heroku上使用机架/缓存来缓存超过1MB的文件?

时间:2013-07-15 14:42:27

标签: ruby-on-rails caching heroku memcached dragonfly-gem

我正在使用Heroku上托管的Dragonflyrack/cache的组合。

我正在使用Dragonfly上传资源。缩略图即时处理并存储在机架/缓存中,以便从memcached(通过Memcachier addon)快速传送。

常规静态资产也通过rack / cache缓存在memcached中。

我的问题是,任何超过1MB的上传文件都会导致我的应用程序出现500错误。

2013-07-15T10:38:27.040992+00:00 app[web.1]: DalliError: Value too large, memcached can only store 1048576 bytes per key [key: d49c36d5db74ef45e957cf169a0b27b83b9e84de, size: 1502314]
2013-07-15T10:38:27.052255+00:00 app[web.1]: cache: [GET /media/BAhbBlsHOgZmSSIdNTA3Njk3ZWFiODBmNDEwMDEzMDAzNjA4BjoGRVQ/WTW_A5Flyer_HealthcareMedicalObsGynae_WEB.pdf] miss, store
2013-07-15T10:38:27.060583+00:00 app[web.1]: !! Unexpected error while processing request: undefined method `each' for nil:NilClass

Memcache的限制为1MB,因此我可以理解为什么我的资产没有被缓存,但我宁愿它不会破坏服务资产。

我甚至不确定这个错误来自哪里。大概来自其他一个机架中间件?

增加最大文件大小似乎没有任何影响。

config.cache_store = :dalli_store, ENV["MEMCACHIER_SERVERS"].split(","), {¬
  :username        => ENV["MEMCACHIER_USERNAME"],¬
  :password        => ENV["MEMCACHIER_PASSWORD"],¬
  :value_max_bytes => 5242880 # 5MB¬
}

从长远来看,我知道将这种资产从Heroku中移除是一个明智的举动,但这不会是一个快速的工作。

在此期间我可以做什么来在Heroku上提供这些资产而不会出错?

3 个答案:

答案 0 :(得分:9)

与@ jordelver的问题相反,我发现设置dalli的:value_max_bytes选项确实有效。我正在以稍微不同的方式设置Rack :: Cache,这可能会产生不同。

这是我的production.rb包含的配置Rack :: Cache:

client = Dalli::Client.new(ENV["MEMCACHIER_SERVERS"],
                           :username => ENV["MEMCACHIER_USERNAME"],
                           :password => ENV["MEMCACHIER_PASSWORD"],
                           :value_max_bytes => 10485760)
config.action_dispatch.rack_cache = {
  :metastore    => client,
  :entitystore  => client
}
config.static_cache_control = "public, max-age=2592000"

通过上述操作,一些错误将打印到日志中,超过1MB的值,但它们不会导致客户端出现5xx错误,只会导致缓存未命中。

P.S我为MemCachier工作:)所以我们有兴趣尝试解决这个问题。如果有效,请告诉我。

答案 1 :(得分:7)

我和@jordelver有同样的问题,并设法通过猴子修补Dragonfly::Response获得了memcachier的限制:

module Dragonfly
  class Response
    private
    def cache_headers
      if job.size > 1048576
        {
          "Cache-Control" => "no-cache, no-store",
          "Pragma" => "no-cache"
        }
      else
        {
           "Cache-Control" => "public, max-age=31536000", # (1 year)
           "ETag" => %("#{job.signature}")
        }
      end
    end
  end
end

基本上,如果大小超过1048576字节,则发送无缓存标头。

答案 2 :(得分:0)

我的application.js对于rack-cache来说太大了,所以我做了:

# in config/environments/development.rb
config.action_dispatch.rack_cache = {
  metastore: 'file:/var/cache/rack/meta',
  entitystore: 'file:tmp/cache/rack/body'
}

它有效!

在memcache中存储元数据,但在文件系统中存储实际文件而不在内存中。