首页 > 解决方案 > 尽管 expires_in 24.hours,Rails 缓存值丢失/为零

问题描述

我正在使用带有 Puma 的 ruby​​ 2.3.3 和 Rails 4.2.8(1 个工人,5 个线程),在我的管理(即非关键)页面上,我想从我的数据库中显示一些统计信息(整数值)。有些请求需要很长时间才能执行,所以我决定缓存这些值并使用 rake 任务每天重写它们。

Admin#index 控制器

require 'timeout'
begin
  timeout(8) do
    @products_a = Rails.cache.fetch('products_a', :expires_in => 24.hours) { Product.where(heavy_condition_a).size }

    @products_b = Rails.cache.fetch('products_b', :expires_in => 24.hours) { Product.where(heavy_condition_b).size }
    @products_c = Rails.cache.fetch('products_c', :expires_in => 24.hours) { Product.where(heavy_condition_c).size }
    @products_d = Rails.cache.fetch('products_d', :expires_in => 24.hours) { Product.where(heavy_condition_d).size }              
  end
rescue Timeout::Error
  @products_a = 999
  @products_b = 999
  @products_c = 999
  @products_d = 999   

end

管理员#index 视图

    <li>Products A: <%= @products_a %></li>
    <li>Products B: <%= @products_b %></li>
    <li>Products C: <%= @products_c %></li>
    <li>Products D: <%= @products_d %></li>

耙任务

task :set_admin_index_stats => :environment do
    Rails.cache.write('products_a', Product.where(heavy_condition_a).size, :expires_in => 24.hours)
    Rails.cache.write('products_b', Product.where(heavy_condition_b).size, :expires_in => 24.hours)
    Rails.cache.write('products_c', Product.where(heavy_condition_c).size, :expires_in => 24.hours)
    Rails.cache.write('products_d', Product.where(heavy_condition_d).size, :expires_in => 24.hours)                     
end

我在生产中使用它并使用 Memcachier(在 Heroku 上)作为缓存存储。我还将它用于网站上的页面缓存,并且在那里工作正常。我有:

生产.rb

config.cache_store = :dalli_store

我遇到的问题是缓存的值几乎立即从缓存中消失,而且是断断续续的。在我尝试过的控制台中:

  1. 我 Rails.cache.write 一个值(例如 product_a)并在一分钟后检查它,它仍然存在。虽然很粗糙,但我可以在 Memcachier 管理工具中看到“设置 cmds”的增量为 1。
  2. 但是,当我添加下一个值(例如 product_b)时,第一个值会消失(变为 nil)!有时,如果我添加所有 4 个值,2 似乎坚持。这些值并不总是相同的。就像打地鼠一样!
  3. 如果我运行 rake 来写入值,然后尝试读取这些值,通常只剩下两个值,而其他值则丢失。

我看到了一个与此相关的类似问题,其中解释的原因是使用了多线程服务器。缓存的值保存在一个线程中,无法在另一个线程中访问,解决方案是使用 memcache,我这样做了。

它不仅是控制台。如果我只是重新加载 admin#index 视图来存储值或运行 rake 任务,我会遇到同样的问题。价值观不会坚持。

我怀疑我要么没有正确使用 Rails.cache-commands,要么这些命令实际上没有使用 Memcachier。我无法确定我的值是否实际上存储在 Memcachier 中,但是当我在控制台中使用我的第一个命令时,我确实得到了以下信息:

Rails.cache.read('products_a')
Dalli::Server#connect mc1.dev.eu.ec2.memcachier.com:11211
Dalli/SASL authenticating as abc123
Dalli/SASL authenticating as abc123
Dalli/SASL: abc123
Dalli/SASL: abc123
=> 0

但我没有得到后续写入的信息(我认为这是控制台中的可读性问题,而不是没有使用 Memcachier 的证明。

我在这里想念什么?为什么这些值不会保留在我的缓存中?

标签: ruby-on-railsrubycachingmemcachier

解决方案


Heroku DevCenter声明了一些不同的缓存配置,并提供了一些关于线程化 Rails 应用服务器的建议,例如Puma使用connection_poolgem:

config.cache_store = :mem_cache_store,
  (ENV["MEMCACHIER_SERVERS"] || "").split(","),
  { :username => ENV["MEMCACHIER_USERNAME"],
    :password => ENV["MEMCACHIER_PASSWORD"],
    :failover => true,
    :socket_timeout => 1.5,
    :socket_failure_delay => 0.2,
    :down_retry_delay => 60,
    :pool_size => 5
  }

推荐阅读