如何在Heroku上使用rack/cache缓存1MB以上的文件?

8
我正在使用在Heroku上托管的Dragonflyrack/cache的组合。
我使用Dragonfly上传资产。缩略图是即时处理的,并存储在rack/cache中,以便通过Memcachier addon从memcached快速交付。
常规静态资产也通过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的限制,所以我可以理解为什么我的资源没有被缓存,但我希望它不会影响服务资产。
我甚至不确定这个错误来自哪里。可能是其他rack中间件之一吗?
增加最大文件大小似乎没有任何影响。
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个回答

10

与@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错误,只是导致缓存未命中。

附言:我在MemCachier工作,我们很想尝试解决这个问题。如果它有效,请告诉我。


将 value_max_bytes 值设置得更高并没有在我的情况下起作用。 - Francois
这帮助我在一个稍微不同的问题上找到了正确的方向,所以谢谢 David :) - robotmay
要以这种方式做,您必须安装rack-cache gem。通常,您可以通过添加config.cache_store =:dalli_storeenvironments/development.rb中打开dalli。您能否在此处指定value_max_bytes的值?谢谢。 - Zack Xu
1
可以的,config.cache_store = :dalli_store, ENV['MEMCACHIER_SERVERS'], { :value_max_bytes => 1048760 } - David Terei

8

我和 @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字节,则发送一个no-cache头。

1
FYI,有一种API可以更改头文件而无需猴子补丁 - 请参见http://markevans.github.io/dragonfly/configuration/(“response_header”部分)。 - Mark Evans

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中,但实际文件存储在文件系统中而不是内存中。


1
如果你在Heroku上运行,这不是一个好主意,因为Dynos将共享元数据存储但不共享文件系统。这意味着有时根据元数据存储缓存了你的文件,但在文件系统中却找不到它,导致无法被发现。 - jordelver
你推荐在Memcache中存储文件吗? - Dorian
顺便说一下,这是针对 development.rb 的。 - Dorian
我改用本地文件系统来存储元数据。 - Dorian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接