快取對於提高Web應用程式的效能和可擴充套件性至關重要–Ruby on Rails中的快取也不例外。通過儲存和重複使用昂貴的計算或資料庫查詢的結果,快取大大減少了服務使用者請求所需的時間和資源。
在這裡,我們回顧瞭如何在Rails中實現不同型別的快取,如片段快取和俄羅斯娃娃快取。我們還將向你展示如何管理快取依賴和選擇快取儲存,並概述在Rails應用程式中有效使用快取的最佳實踐。
本文假定你熟悉Rails上的Ruby,使用Rails版本6或更高,並能自如地使用Rails檢視。程式碼示例演示瞭如何在新的或現有的檢視模板中使用快取。
- Ruby on Rails的快取型別
- Ruby on Rails中的片段快取
- Ruby on Rails中的俄羅斯娃娃快取
- Ruby on Rails中的快取依賴管理
- Ruby on Rails中的快取儲存和後端
- Ruby on Rails快取的最佳實踐
Ruby on Rails的快取型別
在Ruby on Rails應用程式中,根據快取內容的級別和粒度,有幾種快取型別可供選擇。現代Rails應用程式中使用的主要型別有
- 片段快取(Fragment caching):快取網頁中不經常變化的部分,如頁首、頁尾、側邊欄或靜態內容。片段快取減少了每次請求中渲染的部分或元件的數量。
- 俄羅斯娃娃快取(Russian doll caching):快取網頁中相互依賴的巢狀片段,如集合和關聯。俄羅斯娃娃快取可防止不必要的資料庫查詢,並可輕鬆重用未更改的快取片段。
另外兩種型別的快取以前是Ruby on Rails的一部分,但現在可以作為單獨的寶石使用:
- 頁面快取(Page caching):將整個網頁作為靜態檔案快取在伺服器上,繞過整個頁面渲染生命週期。
- 動作快取(Action caching):快取整個控制器動作的輸出。它與頁面快取類似,但允許您應用過濾器,如身份驗證。
頁面快取和動作快取很少使用,在現代Rails應用程式的大多數用例中不再推薦使用。
Ruby on Rails中的片段快取
片段快取允許您快取頁面中不經常變化的部分。例如,一個顯示產品列表及其相關價格和評價的頁面可以快取不太可能改變的細節。
同時,它可以讓Rails在每次頁面載入時重新渲染頁面的動態部分(如評論或評價)。當檢視的底層資料頻繁變化時,由於頻繁更新快取的開銷,片段快取就不那麼有用了。
作為Rails中最簡單的快取型別,片段快取應該是你為應用程式新增快取以提高效能的首選。
要在Rails中使用片段快取,請在檢視中使用快取輔助方法。例如,編寫以下程式碼來快取檢視中的產品部分:
<% @products.each do |product| %> <% cache product do %> <%= render partial: "product", locals: { product: product } %> <% end %> <% end %>
cache
助手根據每個元素的類名、 id
和 update_at
時間戳(例如, products/1-20230501000000
)生成一個快取鍵。下一次使用者請求相同的產品時, cache
助手將從快取儲存中獲取快取片段並顯示出來,而無需從資料庫中讀取產品。
您也可以通過向 cache
助手傳遞選項來自定義快取鍵。例如,要在快取金鑰中包含版本號或時間戳,可以這樣寫
<% @products.each do |product| %> <% cache [product, "v1"] do %> <%= render partial: "product", locals: { product: product } %> <% end %> <% end %>
或者,您也可以設定到期時間:
<% @products.each do |product| %> <% cache product, expires_in: 1.hour do %> <%= render partial: "product", locals: { product: product } %> <% end %> <% end %>
第一個示例將在快取鍵(例如, products/1-v1
)上新增 v1
。當您更改部分模板或佈局時,這對快取失效非常有用。第二個示例為快取條目設定了過期時間(1小時),這有助於過期資料的失效。
Ruby on Rails中的俄羅斯娃娃快取
俄羅斯娃娃快取是Ruby on Rails中一種強大的快取策略,它通過相互巢狀快取來優化應用程式的效能。它使用Rails的片段快取和快取依賴來減少冗餘工作,提高載入時間。
在一個典型的Rails應用程式中,您經常渲染一個專案集合,每個專案都有多個子元件。更新單個專案時,應避免重新渲染整個集合或任何未受影響的專案。在處理分層或巢狀資料結構時,尤其是當巢狀元件有自己的關聯資料且可能獨立變化時,請使用Russian Doll快取。
俄羅斯娃娃快取的缺點是增加了複雜性。您必須瞭解您要快取的專案的巢狀層之間的關係,以確保您快取了正確的專案。在某些情況下,您需要在Active Record模型中新增關聯,以便Rails可以推斷快取資料項之間的關係。
與常規的片段快取一樣,俄羅斯娃娃快取使用 cache
輔助方法。例如,在檢視中快取一個類別及其子類別和產品,可以這樣寫:
<% @categories.each do |category| %> <% cache category do %> <h2><%= category.name %></h2> <% category.subcategories.each do |subcategory| %> <% cache subcategory do %> <h3><%= subcategory.name %></h3> <% subcategory.products.each do |product| %> <% cache product do %> <%= render partial: "product", locals: { product: product } %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %>
cache
助手會將每個巢狀層分別儲存在快取中。下一次請求同一類別時,它將從快取儲存中獲取其快取片段並顯示出來,而無需再次渲染。
然而,如果任何子類別或產品的詳細資訊發生變化(如名稱或描述),則其快取片段將失效,然後將使用更新的資料重新渲染。俄羅斯娃娃快取確保您不必在單個子類別或產品發生變化時使整個類別失效。
Ruby on Rails中的快取依賴管理
快取依賴關係是快取資料與其底層源之間的關係,對其進行管理可能非常棘手。如果源資料發生變化,任何相關的快取資料都會過期。
Rails可以使用時間戳來自動管理大多數快取依賴關係。每個Active Record模型都有 created_at
和 updidated_at
屬性,指示快取建立或最後更新記錄的時間。為了確保Rails可以自動管理快取,請定義你的Active Record模型的關係如下:
class Product < ApplicationRecord belongs_to :category end class Category < ApplicationRecord has_many :products end
在此示例中:
- 如果您更新了一個產品記錄(例如,通過改變它的價格),它的
updated_at
時間戳會自動改變。 - 如果您使用該時間戳作為快取鍵的一部分(如
products/1-20230504000000
),它也會自動使您的快取片段失效。 - 當您更新一個產品記錄時–也許是因為它顯示了像平均價格這樣的聚合資料–要使您的類別的快取片段失效,請使用控制器中的
touch
方法(@product.category.touch
)或在您的模型關聯中新增一個觸控選項(belongs_to :category touch: true
)。
另一種管理快取依賴的機制是直接在模型或控制器中使用低階快取方法–例如 fetch
和 write
。這些方法允許您使用自定義鍵和選項在快取中儲存任意資料或內容。例如
class Product < ApplicationRecord def self.average_price Rails.cache.fetch("products/average_price", expires_in: 1.hour) do average(:price) end end end
本示例演示瞭如何使用 fetch
方法和自定義鍵( products/average_price
)以及過期選項( expires_in: 1.hour
)將計算資料(例如所有產品的平均價格)快取一小時。
fetch
方法將首先嚐試從快取中讀取資料。如果找不到資料或資料已過期,則執行塊並將結果儲存到快取中。
要在快取條目過期前手動使其失效,請使用帶有 force
選項的 write
方法:
Rails.cache.write("products/average_price", Product.average(:price), force: true))
Ruby on Rails中的快取儲存和後端
Rails允許你選擇不同的快取儲存或後端來儲存快取資料和內容。Rails的快取儲存是一個抽象層,提供了與不同儲存系統互動的通用介面。快取後端為特定的儲存系統實現快取儲存介面。
Rails支援多種型別的快取儲存或後端,詳情如下。
記憶體儲存
記憶體儲存使用記憶體中的雜湊作為快取儲存。它快速、簡單,但容量和永續性有限。這種快取儲存適用於開發和測試環境或小型、簡單的應用程式。
磁碟儲存
磁碟儲存使用磁碟上的檔案作為快取儲存。它是Rails中速度最慢的快取選項,但容量和永續性較大。磁碟儲存適用於必須快取大量資料但不需要最高效能的應用程式。
Redis
Redis儲存使用Redis例項進行快取儲存。Redis是一種記憶體資料儲存,支援多種資料型別。雖然它快速靈活,但需要單獨的伺服器和配置。它適用於必須快取經常變化的複雜或動態資料的應用程式。當在雲中執行Rails應用程式時,Redis是一個理想的選擇,因為包括Kinsta在內的一些託管服務提供商提供Redis作為持久物件快取。
Memcached
Memcached儲存使用Memcached例項進行快取儲存。Memcached是一種記憶體鍵值儲存,支援簡單的資料型別和功能。它速度快、可擴充套件,但與Redis一樣,需要單獨的伺服器和配置。該儲存適用於需要快取頻繁更新的簡單或靜態資料的應用程式。
你可以在Rails環境檔案(例如config/environments/development.rb)中使用 config.cache_store
選項配置快取儲存。下面是如何使用Rails內建的每種快取方法:
# Use memory store config.cache_store = :memory_store # Use disk store config.cache_store = :file_store, "tmp/cache" # Use Redis config.cache_store = :redis_cache_store, { url: "redis://localhost:6379/0" } # Use Memcached config.cache_store = :mem_cache_store, "localhost"
每個環境檔案只能呼叫一次 config.cache_store
。如果呼叫了多個,快取儲存只會使用最後一個。
每個快取儲存都有其獨特的優缺點,這取決於您的應用程式的需求和偏好。選擇一個最適合您的使用情況和經驗水平的。
Ruby on Rails快取的最佳實踐
在Rails應用程式中使用快取可以大大提高其效能和可擴充套件性,尤其是當您實施以下最佳實踐時:
- 有選擇地快取:僅快取頻繁訪問、生成成本高或更新頻率低的資料。避免過度快取,以防止記憶體使用過多、資料陳舊和效能下降。
- 過期快取條目:通過過期失效或不相關的條目來防止資料過期。使用時間戳、過期選項或手動失效。
- 優化快取效能:選擇適合您的應用需求的快取儲存,並微調其引數,如大小、壓縮或序列化,以獲得最佳效能。
- 監控和測試快取影響:評估快取行為(如命中率、未命中率和延遲),並評估其對效能(響應時間、吞吐量、資源使用)的影響。使用New Relic、Rails日誌、ActiveSupport通知或Rack mini profiler等工具。
小結
Ruby on Rails快取通過有效地儲存和重複使用經常訪問的資料或內容來提高應用程式的效能和可擴充套件性。通過深入瞭解快取技術,您可以更好地為使用者提供更快的Rails應用程式。
評論留言