Rails 聊聊 Rails 中的 Cache Stores

lanzhiheng · 2022年12月17日 · 最后由 amonlei 回复于 2022年12月22日 · 700 次阅读

最近被 Rails 的缓存坑得有点惨,笔者只知道缓存要启动,却忘记缓存要合适才有意义。这篇文章简单聊聊Cache Stores。原文链接:https://step-by-step.tech/posts/cache-stores-in-rails

4FFFF00B-6529-40E0-9D92-FD350385427E-10705-00000724CC22ADAB.JPG

开发环境缓存

一般来说在开发环境并不需要打开缓存,只不过有时候为了调试缓存的线上效果,需要在开发环境打开缓存功能。开启的方式也很简单,直接本地运行命令bin/rails dev:cache

> bin/rails dev:cache
Development mode is now being cached.

>  bin/rails dev:cache
Development mode is no longer being cached.

运行结果会提示你,开发模式是否已经开启了缓存。其实打开文件config/environments/development.rb,可以看到这么一段代码

Rails.application.configure do
  ....
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
    config.action_controller.perform_caching = true
    config.action_controller.enable_fragment_cache_logging = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }
  else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
  end
end

原理很简单,如果tmp/caching-dev.text这个文件存在表示缓存已经开启,否则的话表示开发环境不开启缓存,所以你也可以通过命令

> touch tmp/caching-dev.txt

开启开发环境的缓存,再通过命令

> rm tmp/caching-dev.txt

来关闭开发环境的缓存,效果跟官方脚本是一样的。

从配置config.cache_store = :memory_store可以看出,当前采用的 Cache Store 是memory_store。具体文档可以看这里。也可以通过内省的方式查看

> Rails.cache
=> <#ActiveSupport::Cache::MemoryStore entries=0, size=0, options={}>

可见开发环境的缓存存储器是ActiveSupport::Cache::MemoryStore对应了memory_store,也就是把缓存内容存放在机器的内存里面。配置起来相对比较简单,毕竟每台机器都有内存资源,只要设置最大的存储区大小即可

config.cache_store = :memory_store, { size: 64.megabytes }

不需要别的额外配置。

线上环境缓存

这里说的线上环境,指的是生产环境或者预生产环境。一般这种环境的配置文件都跟config/environments/production.rb有点类似,

关于缓存存储器的代码,都是注释掉的

Rails.application.configure do
  # config.cache_store = :mem_cache_store
end

也就是都是采用缺省配置。然而笔者没想到的是原来缺省配置是file_store。这是我在生产环境下内省得到的结果

> Rails.application.config.cache_store
=> [:file_store, "/www/project/huiliu-web/tmp/cache/"]

也就是说缓存结果会持久化到目录/www/huiliu/huiliu-web/tmp/cache/中,笔者的上一篇文章提到的inode number导致的空间不足,其实就是这个导致的。系统运行时间长,缓存持久化文件过多,且没有定时清理,导致inode number耗尽。现在回想起来主要原因还是笔者没有用到合适的缓存存储器。

选择合适的缓存

Rails 提供的缓存存储器主要是这几个,文档都有相应说明

  1. memory_store。缓存都是存在内存里面,无法在多台机器之间共享。适合小规模单机运行的环境。
  2. file_store。缓存持久化到文件系统中,只要多台机器能够共同访问同一个文件系统。这些缓存可以多机器之间共享。
  3. mem_cache_store。使用第三方服务Memcached,看着应该是跟 Redis 挺像的一个服务,需要一定的配置。
  4. redis_cache_store。使用第三方服务Redis,比较常用的 NoSQL 数据库,也需要一定的配置。
  5. null_store。完全不使用缓存。
  6. 自定义。

自定义就是指可以根据自己的需求去实现缓存存储器的适配器。大伙可以根据自己的实际情况进行选择,不管怎么说,笔者强烈不建议使用file_store,如果真的需要多台机器之间共享缓存,那么使用mem_cache_store或者redis_cache_store并购买相关的第三方服务可能是更好的选择。简单起见,在笔者现有的项目里面,使用memory_store就好。因为笔者现在的机器内存还算是比较有盈余的,所以设置得大一点

Rails.application.configure do
  config.cache_store = :memory_store, { size: 1024.megabytes } # 2048问题也不大
end

根据memory_store的说法是,当缓存量超出设定的值的时候,会优先淘汰最久未被访问过的缓存数据。其实就是Least recently used (LRU)算法,原文是这样的

When the cache exceeds the allotted size, a cleanup will occur and the least recently used entries will be removed.

不一定一开始就上mem_cache_store或者redis_cache_store,有时候简单能用不失为一个更好的选择。

总结

这篇文章简单聊了一下 Rails 服务里面的缓存存储器,这些引擎主要是针对部分的SQL Caching场景以及Page Caching场景的。这些缓存存储器各有千秋,根据自己的业务场景选择合适自己的就好。

请问怎么测试有没有用到缓存,配置完了,看 log 还都是请求的数据库,也不知道啥时候用到了,是不是要专门写缓存的代码

yfscret 回复

不用啊。开启了就行。

最简单的方式就是,内省一下。

Rails.application.config.cache_store 

有配置缓存存储器就行。如果是 file_store 的话对应的缓存目录下会有缓存文件。没有配置缓存的话,内省会返回null_store

yfscret 回复

主要看你是哪种类型的缓存,一般的话缓存如果命中了,会少很多数据库请求。

lanzhiheng 回复

缓存是确认开启了,但是怎么判断命中没命中,或者怎么知道哪些用上了缓存

yfscret 回复

命中缓存时日志会有提示的。 如果是说页面缓存的话,需要使用 cache 方法,像这样

<% @products.each do |product| %>
  <% cache product do %>
    <%= render product %>
  <% end %>
<% end %>

如果是底层缓存,需要使用 Rails.cache.fetch。

更详细的解答 https://ruby-china.org/topics/27939

除非客户明确提出性能有问题,不然我们一般不会先上缓存。。。😅

spike76 回复

😂 我前期也想停掉。

我好像遇到过,做对 linux 做设置就可以了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号