天天看點

Rails caching(Rails高速緩存)1. 基本緩存2 cache stores3. caching in development

目錄

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.
           

繼續閱讀