【问题标题】:How to cache files over 1MB with rack/cache on Heroku?如何在 Heroku 上使用 rack/cache 缓存超过 1MB 的文件?
【发布时间】:2013-07-13 11:31:43
【问题描述】:

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

我正在使用 Dragonfly 上传资产。缩略图被即时处理并存储在 rack/cache 中,以便从 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 上无错误地提供这些资产?

【问题讨论】:

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


    【解决方案1】:

    我的application.jsrack-cache 来说太大了,所以我做了:

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

    而且它有效!

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

    【讨论】:

    • 如果您在 Heroku 上运行,这不是一个好主意,因为 Dynos 将共享元存储而不是文件系统。这意味着有时您的文件会根据元存储被缓存,但从文件系统中丢失,并且不会被找到。
    • 你推荐将文件存储在 Memcache 中吗?
    • 顺便说一句,这是给development.rb
    • 我也改为使用本地文件系统进行元存储
    【解决方案2】:

    我遇到了与@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 标头。

    【讨论】:

    【解决方案3】:

    所以与@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 工作 :) 所以我们有兴趣尝试解决这个问题。请让我知道它是否有效。

    【讨论】:

    • 设置更高的 value_max_bytes 值在我的情况下不起作用。
    • 这帮助我在一个稍微不同的问题上指出了正确的方向,所以感谢大卫:)
    • 要这样做,你必须安装 rack-cache gem。通常你通过添加config.cache_store = :dalli_store来打开environments/development.rb中的dalli。您可以在这里指定 value_max_bytes 吗?谢谢
    • 是的,你可以,config.cache_store = :dalli_store, ENV['MEMCACHIER_SERVERS'], { :value_max_bytes => 1048760 }
    猜你喜欢
    • 2012-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 2012-03-21
    • 1970-01-01
    • 2013-03-11
    • 2011-05-05
    相关资源
    最近更新 更多