ruby-on-rails - 尽管 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
我遇到的问题是缓存的值几乎立即从缓存中消失,而且是断断续续的。在我尝试过的控制台中:
- 我 Rails.cache.write 一个值(例如 product_a)并在一分钟后检查它,它仍然存在。虽然很粗糙,但我可以在 Memcachier 管理工具中看到“设置 cmds”的增量为 1。
- 但是,当我添加下一个值(例如 product_b)时,第一个值会消失(变为 nil)!有时,如果我添加所有 4 个值,2 似乎坚持。这些值并不总是相同的。就像打地鼠一样!
- 如果我运行 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 的证明。
我在这里想念什么?为什么这些值不会保留在我的缓存中?
解决方案
Heroku DevCenter声明了一些不同的缓存配置,并提供了一些关于线程化 Rails 应用服务器的建议,例如Puma
使用connection_pool
gem:
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
}
推荐阅读
- ios - 隐藏导航控制器搜索栏并以编程方式打开大标题
- java - 在不丢失对象引用的情况下内联调用 setter
- angular - 如何在每个按钮单击时将数据附加到列表中:Angular typescript + Laravel
- elasticsearch - Logstash:使用日志文件的行号作为 document_id
- ios - 字符串匹配正则表达式模式,但通过范围提取子字符串后返回结果为零
- amazon-web-services - 实现预定推送通知的最佳方式
- c# - 在 Process.StandardOutput 中获取和设置位置
- grails - Grails 3.3.8 不会重新加载对项目所做的更改
- freeswitch - 具有 10 位以上正则表达式验证的免费 Switch?
- sql-server - 如果 DDL 触发器中不支持条件