当前位置: 首页 > 工具软件 > Rails > 使用案例 >

Rails caching(Rails高速缓存)

解晟睿
2023-12-01

目录

 

1. 基本缓存

1.1 page caching

1.2 action caching

1.3 fragment caching

1.4 俄罗斯套娃caching

1.5 共享部分caching

1.6 管理依赖

1.7 低级别caching

1.8 sql caching

2 cache stores

2.1 configuration

2.2 activesupport::cache::store

2.2.1 connection pool options

2.2.2 定义化cache stores

2.3 activesupport::cache::memorystore

2.4 activesupport::cache::filestore

2.5 activesupport::cache::memcachestore

2.6 activesupport::cache::rediscachestore

2.7 activesupport::cache::nuillstore

3. caching in development



本文将介绍如何通过高速缓存机制来加速Rails程序应用。

高速缓存意味着在request-response这个cycle里生成存储数据,然后在反馈相似的请求时复用。

缓存机制是提高应用性能的最高效的机制。通过缓存机制,连接单数据库的单服务器能够支持千级并发。

Rails提供了一系列的开箱即用的caching特性。 本手册将介绍介绍每个特性的范围和目的。

通过阅读本文,你会学到:

  • 片段和俄罗斯套娃缓存
  • 怎么解决缓存依赖
  • 备用缓存存储
  • 条件Get支撑

1. 基本缓存

本段将介绍三种类型的缓存技术: page, action和fragment缓存。默认,Rails提供了片段缓存。为了使用page和action的caching机制,需要在Gemfile中添加actionpack-page_caching和actionpack-action_caching。

默认,caching只在production环境中使用。如果想在本地使用缓存机制,就需要在本地config/environments/*.rb文件中配置config.action_controller.perform_caching=true。这个值的改变仅会影响

Action Controller中的caching,而不会影响到实例中的低级别的caching。

1.1 page caching

page caching允许请求生成一个web page的请求。由于这是特别块的,所以其并不适用于每一个情况,例如认证。这时候的访问就像从一个文件系统直接获取文件,则为了安全期间,我们需要设置cache的失效期。

需要注意的是, page caching已经从Rails 4.0中移除。

1.2 action caching

如上段所说,page caching不能用于filter之前的actions。例如,需要认证的pages,这就是为什么会有action caching。

需要注意的是,action caching也已经从Rails 4.0中移除。

1.3 fragment caching

动态的web应用通常会基于许多组件(存储机制不同)来生成pages。当page中不同部分需要cached,并且需要不同的生命周期时,则需要使用fragment caching。

fragment caching允许view的段落可以被包装成一个cache block然后当下一个请求来的时候从cache store中取出来。

例如,可以用以下代码来cache页面中的每一个product:

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

当你的应用收到关于这个界面的第一个请求时,Rails会基于唯一键写一个新的cache,例如

views/products/index:bea67108094918eeba42cd4a6e786901/products/1

这个中间的hash字符是基于我们caching的view片段的内容计算出来的。如果这个view片段发生改变,hash字符都会改变,老的cache则会失效,且会从cache stores里删除。

如果想基于某个条件cache某个片段,则可以使用‘cache_if’或者'cache_unless'。

<% cache_if admin?, product do %>
  <%= render product %>
<% end %>

除了单个cache,也可以集合方式cache,如下:

<%= render partial: 'products/product', collection: @products, cached: true %>

1.4 俄罗斯套娃caching

cache也是可以嵌套的,这叫做俄罗斯套娃caching。

俄罗斯套娃caching的优势在于:如果单一产品更新了,其他内嵌的片段可以被重复使用用于生成外部的片段。

当一个cached文件的updated_at变化了,则这个cache就失效了,但是。其内部镶嵌的片段都却不会过期。如下片段:

<% cache product do %>
  <%= render product.games %>
<% end %>

当game的任一属性改变了,则updated_at会设置成当前时间,然后game的cache会过期。然而,相关联的product会不会因此而过期,从而产生陈旧数据,这是不正确的。

则为了解决这个问题, 我们需要用touch方法将这两个主题连接起来。

class Product < ApplicationRecord
  has_many :games
end

class Game < ApplicationRecord
  belongs_to :product, touch: true
end

这样的话,任何game的变化都会引起相关联的product的cache的更新。

1.5 共享部分caching

共享部分cachings也是有可能实现的。例如,共享部分caching允许模版在html和javascripts文件件共享部分文件。

1.6 管理依赖

为了正确的废止cache,我们需要正确定义caching依赖。Rails默认能处理一般例子,然而,有时,当你处理定制化的helpers时,则需要显示定义他们。

隐式依赖定义:

 

render @project.documents.where(published: true)

 

显示依赖定义:

<%# Template Collection: notification %>
<% my_helper_that_calls_cache(some_arg, notification) do %>
  <%= notification.name %>
<% end %>

 

1.7 低级别caching

有时,我们不需要去cocah view的片段,而仅仅需cache一个值或者query的结果。幸运的是,rails的caching机制支持保存任何信息。

最高效的实现底层caching则需要用rails.cache.fetch方法。这个方法支持读写cache。当参数是一个值时,则key被获取,caches里的值被返回。如果参数是一个块,则没有cache时,该代码块会被执行,然后返回值会被写进cache。

如下例子:

class Product < ApplicationRecord
  def competing_price
    Rails.cache.fetch("#{cache_key_with_version}/competing_price", expires_in: 12.hours) do
      Competitor::API.find_price(id)
    end
  end
end

1.8 sql caching

query caching缓存每一个query返回的查找结果。如果rails遇到相同的query,则会使用cached的值,而不会再次查询。

例如:

class ProductsController < ApplicationController

  def index
    # Run a find query
    @products = Product.all

    ...

    # Run the same query again
    @products = Product.all
  end

end

这二次去数据库执行相同的查询,但是并不是去真正的访问数据库。第一次查询返回的结果存储在query cache里面(内存里),第二次会直接从内存中获取到。

然而,查询caches在一个action开始的时候创建,在action结束的时候销毁,所以仅仅存在在一个action的生命周期里。如果你希望这个查询结果保存的更长久,则可以使用low-level caching。

2 cache stores

除了sql和page caching,rails为不同的存储数据存储了不同的存储。

2.1 configuration

你可以通过设置config.cache_store配置选项来配置应用程序默认的cache store。如下:

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

除了这种方法,你还可以在configuration块外调用actioncontroller::base.cache_store去定义cache store.

还可以通过rails cache去获取cache。

2.2 activesupport::cache::store

这个类提供了rails中cache交互基础。这个是抽象类,我们不能直接使用。我们在具体化类时需要和存储引擎绑定。

主要方法包括:read, write, delete, exist?和 fetch。

2.2.1 connection pool options

默认的,MemCacheStore和RedisCacheStore使用一个单一的连接进程。如果想增加可用连接的数字,则使能connection pooling。

第一步,在Gemfile文件中添加connection_pool 

gem 'connection_pool'

然后,在配置cache store时陪你pool_size和pool_timeout,如下:

config.cache_store = :mem_cache_store, "cache.example.com", { pool_size: 5, pool_timeout: 5 }

2.2.2 定义化cache stores

我们可以通过继承activesupport::cache::store来创建自己的cache store。如下实例化类:

config.cache_store = MyCacheStore.new

2.3 activesupport::cache::memorystore

这个cache stor保存在同一进程中的实例在内存中。我们可以通过以下配置类初始化cache store。默认大小为32m,当所占的内存超过该值时,则使用最少的一些值会被清除。

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

如果rails应用多程序运行譬如用了phusion passenger,则rails server process实例间无法共享cache 数据。这种cache store对大型应用的部署并不适用。而对于small, low traffic的网站,却能很好的适用。

由于当我们使用:memory_store,进程间无法共享进程,所以我们无法通过rails console去手动的读写或者失效cache。

2.4 activesupport::cache::filestore

这种cache store用文件系统去存储实体。如下:

config.cache_store = :file_store, "/path/to/cache/directory"

如果我们没有如上设定位置,则cache默认会存储在“#{root}/tmp/cache”目录下

2.5 activesupport::cache::memcachestore

这个cache store用danga's memcached 服务器为服务提供了中心化的缓存。rails默认用了dundled dalli gem。这是目前对production网站最流行的cache store。他可以用来提供单一的,共享的高性能高冗余的cache集群。

当初始化cache时,你需要指定集群中memcached servers的地址,如下:

config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com"

如果不指定地址,则默认为本地(如下),对于小网站,这样是可以的,但是对于大型应用是不可以的。、

config.cache_store = :mem_cache_store # Will fallback to $MEMCACHE_SERVERS, then 127.0.0.1:11211

2.6 activesupport::cache::rediscachestore

redis cache store的优势是当达到最大存储空间会自动清理。我们需要在gemfile中添加redis gem。如下:

gem 'redis'

我们可以使能更快的hiredis链接库。我们需要在gemfile中添加hiredis gem。如下:

gem 'hiredis'

redis cache store会自动需要和使用hiredis。而不需要其他更多额外的配置。

2.7 activesupport::cache::nuillstore

这个cache store的实现意味着其仅在development和test环境中使用,且不存储任何东西。这在开发时是很有用的,你可以通过rails.cache直接看到代码的变化。

config.cache_store = :null_store

3. caching in development

我们说了通常cache只在production环境中有效,当我们想在开发环境中测试我们的cache机制时,rails提供了dev:cache去方便的打开和关闭caching。如下:

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

 

 类似资料: