代码之家  ›  专栏  ›  技术社区  ›  Ben Crouse

带memcache的Rails返回错误的缓存对象?

  •  6
  • Ben Crouse  · 技术社区  · 15 年前

    我有一个相当大的Rails应用程序,它使用单独服务器上的memcached作为缓存存储。

    问题是我在生产环境中随机得到错误, 似乎 以指示memcached返回的对象不正确。

    实例:

    在这个例子中, current_site 是一个辅助方法,它访问 Site 使用rails.cache缓存模型的模型

    ActionView::TemplateError in ListingsController#edit
    undefined method `settings' for #<String:0xb565f8a0>
    
    On line #12 of app/views/layouts/site.html.erb
    
        9:         <meta name="robots" content="noodp, all" />
        10:         <meta name="distribution" content="Global" />
        11: 
        12:         <% unless current_site.settings[:google_webmaster_verification_code].blank? %>
        13:         <meta name="verify-v1" content="<%= current_site.settings[:google_webmaster_verification_code] %>" />
        14:         <% end %>
        15: 
    

    与……形成对比。

    ActionView::TemplateError in ApplicationController#not_found
    undefined method `settings' for #<Category:0xd5c6c34>
    
    On line #12 of app/views/layouts/site.html.erb
    
        9:         <meta name="robots" content="noodp, all" />
        10:         <meta name="distribution" content="Global" />
        11: 
        12:         <% unless current_site.settings[:google_webmaster_verification_code].blank? %>
        13:         <meta name="verify-v1" content="<%= current_site.settings[:google_webmaster_verification_code] %>" />
        14:         <% end %>
        15: 
    

    当两者都应该返回 现场 模特!

    缓存行为异常的另一个例子:

    ActionView::TemplateError in AccountsController#show
    can't convert Category into String
    
    On line #141 of app/views/layouts/site.html.erb
    
        138:                    <li<%=  class="first" if i == 0 %>><%= link_to top_level_category.title, top_level_category.path %></li><% end %>
        139:                </ul>
        140:            <% end %>
        141:            <% cache bottom_pages do %>
        142:                <ul><% Page.top_level.active.show_in_navigation.find(:all, :include => :slugs).each_with_index do |top_level_page, i| %>
        143:                    <li<%=  class="first" if i == 0 %>><%= link_to top_level_page.title, top_level_page.path %></li><% end %>
        144:                </ul>
    

    以前有人遇到过这样的事情吗?有人想诊断这个无法解释的问题!我试过换掉memcached客户机gems,认为这可能是一个奇怪的bug,但没有任何效果!谢谢。

    5 回复  |  直到 15 年前
        1
  •  10
  •   Ben Crouse    15 年前

    这是由于乘客共享其与memcached服务器的连接造成的。检查 http://www.modrails.com/documentation/Users%20guide.html#_example_1_memcached_connection_sharing_harmful .

    解决办法就是把乘客的铁轨换成 conservative .

        2
  •  1
  •   Don Werve    15 年前

    一些可能有帮助的事情:

    • 将仪器/日志添加到 current_site 看看到底有什么东西被退回。
    • 如何在memcache中指定密钥?对于两个不同的对象,可能会在两个不同的位置意外地使用相同的键。
    • 使用 memcached-tool host:port dump > /tmp/keys 看看你的memcache里到底有什么。
    • 你的memcached在防火墙后面,没有公开在公共IP上,对吗?
        3
  •  1
  •   avaz    14 年前

    我也遇到了这个问题,在缓存提供程序执行解组操作之前,我解决了为每个类/模型添加Require_依赖项的问题。可能在生产环境中,这不是必需的,因为选项config.cache_class设置为true,但是在测试和开发中,它是false。

    实际上,memcache(我正在使用的缓存提供程序)找不到要执行解组的引用类,然后引发此错误。

    在这篇文章中有一个更好的解决这个问题的方法: http://kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/

    当做!

        4
  •  0
  •   Jérôme Verstrynge Mark    13 年前

    是的,我经历过这种事。和我在一起,是因为我在做 Rails.cache.fetch(key) 钥匙是空白的。

    我在Rails控制台中进行了一些游戏,并使用了以下功能:

    Rails.cache.read validkey  # Get back the proper data
    Rails.cache.fetch('') { 'abc' } # Error in rails log: 'MemCacheError ():'
    Rails.cache.read validkey # Get back nil
    Rails.cache.read validkey # May get back proper data
    
        5
  •  0
  •   Ben Evans    12 年前

    添加评论以防其他人出现…kballcodes.com URL不再有效(尽管您仍然可以通过 archive.org )在那篇博文的评论中,有人描述了一种方法,如果Marshal首先抛出“未定义的类/模块”错误,可以尝试加载有问题的对象。我在下面包含了该代码,并在代码示例下引用了原始作者。

    将此项添加到Rails的初始值设定项文件中\u root/config/initializers/文件夹:

    # 
    # Marshal.load is a C-method built into Ruby; because it's so low-level, it
    # bypasses the full classloading chain in Ruby, in particular the #const_missing
    # hook that Rails uses to auto-load classes as they're referenced. This monkey
    # patch catches the generated exceptions, parses the message to determine the
    # offending constant name, loads the constant, and tries again.
    #
    # This solution is adapted from here:
    # http://kballcodes.com/2009/09/05/rails-memcached-a-better-solution-to-the-undefined-classmodule-problem/
    #
    class <<Marshal
      def load_with_rails_classloader(*args)
        begin
          load_without_rails_classloader(*args)
        rescue ArgumentError, NameError => e
          if e.message =~ %r(undefined class/module)
            const = e.message.split(' ').last
            const.constantize
            retry
          else
            raise(e)
          end
        end
      end
    
      alias_method_chain :load, :rails_classloader
    end
    

    这一切归功于 Matt Brown 是谁制造的 this code as a pastie 并评论了上面这篇已经过世的文章: