Rails.cache相關知識
可能裡面的一些知識已經不被大家使用了,但是作為學習,我想和大家分享一下個人關於Rails.cache的淺顯的認識,望大家指教。
1.Rails.cache是什麼
它是Rails中的快取,擁有所有快取的共同點,它是為了提升網站效能。
2.Rails中Rails.cache的儲存系統。
本身常用的有四種,可以根據不同的環境進行選擇不同的儲存系統。
- FileStore,利用檔案系統快取檔案,能夠在多個應用間共享快取,但是這樣會不斷的增加硬碟使用。
- MemoryStore, Ruby 程序使用共同的記憶體,預設大小為32M,,雖然可以更改這個限制,但是不適合大型的部署,並且它不能用於多個應用共享快取。
- MemCacheStore, 這種方式使用 Memcached 最為後端快取服務,它提供了高效能的、集中式的快取服務,可以在多個應用間共享快取,這是一種適合中大型商業應用的選擇。
- NullStore, 適合開發和測試環境的配置,它不會儲存任何東西,但是可以正常除錯 Rails.cache 中的方法。
3. Rails專案的自定義配置儲存系統。
這裡我以使用redis來作為Rails.cache的儲存系統進行介紹
3.1 為什麼會選redis
因為是key-value的結構,同時使用redis,能夠通過 redis 的命令快速實現,比關係型資料庫擁有更快的讀寫速度,且更適合儲存非結構化資料。
3.2 如何配置
- 確保你的系統已經安裝了redis資料庫(具體怎麼安裝,這裡不做闡述)
- 在你的gemfile檔案中,加入gem 'redis-rails'這一行,然後bundle install。
- 一般初始化的預設配置可以在development.rb,production.rb,test.rb檔案中單獨設定適用於不同環境的儲存系統;我選擇直接在application.rb中寫配置資訊。
配置資訊(必須): config.action_controller.perform_caching = true # 確保開啟快取,dev環境下預設是沒有開啟的。 config.cache_store = :redis_store, { host: 'localhost', port: '6379', db: 1, # 這是整數,可以理解為redis資料庫中的表標誌,預設是16個數據庫,可從0-15中取值 password: '', expires_in: 5.hours # 過期時間的設定 }
4. Rails.cache常見用法。
4.1 首先如何設定開啟快取
production上預設開啟了快取
development上預設不開啟
配置方法一(常用):
# 在development.rb檔案中新增 config.action_controller.perform_caching = true # 設定快取的頁面存放的地址(不能修改,預設是public) config.action_controller.page_cache_directory = "#{Rails.root.to_s}/public"
配置方法二(Rails5版本之後開始支援):
# 執行任務,會在tmp檔案下建立caching-dev.txt和restart.txt檔案 rake dev:cache
經過個人測試,兩者不能混用,混用存在的問題:
1.如果你使用rake dev:cache,就不能在development.rb中去修改快取預設儲存的地址,一旦修改,快取就會失效。
2.一旦你是用rake dev:cache來開啟快取,那麼就要使用rake dev:cache來關閉快取(不能通過config.action_controller.perform_caching = false來操作,無法起作用),如果要自己測試,那你一定要首先把之前快取的檔案給刪除掉,不然不管你怎麼操作,只要public下有該檔案,就一直讀該檔案。如果看一下rake dev:cache的原始碼,我們能找到另外一種方式來關閉
# 原始碼 rake任務 namespace :dev do desc "Toggle development mode caching on/off" task :cache do Rails::DevCaching.enable_by_file end end # 原始碼:通過檔案來判斷是否開啟快取 FILE = "tmp/caching-dev.txt" def enable_by_file FileUtils.mkdir_p("tmp") if File.exist?(FILE) delete_cache_file puts "Development mode is no longer being cached." else create_cache_file puts "Development mode is now being cached." end FileUtils.touch "tmp/restart.txt" end
所以,很明顯,我們可以通過刪除tmp下的restart.txt和cache-dev.txt來關閉快取。
個人建議:還是在development.rb檔案中自己配置比較靈活
4.2 如何使用3種快取方式(片段快取,頁面快取,方法快取),從Rails4開始,頁面快取和方法快取已經轉換為gem的形式,只有片段快取是Rails預設的。
頁面快取
一句話總結:使用快取的頁面來代替action請求對應的頁面,這個和快取系統無關。
預設快取的檔案直接放在public目錄下。頁面快取現在已經被單獨作為一個gem,需要在你的Gemfile中加入 gem "actionpack-page_caching"
真正的程式碼實現:
# 一個控制器 class HuanCunController < ApplicationController # 使用快取 caches_page :welcome_show # 快取的頁面對應的控制器 def welcome_show end end
welcome_show頁面
Hello,welcom!!
current_time_now:<%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %>
沒有使用快取的時候,每次請求的頁面都是實時變化的,可以看current_time_now的值。
使用快取後,會在你配置儲存目錄的檔案下生成對應的靜態html檔案。方法快取
在Gemfile檔案中加入gem 'actionpack-action_caching'
為了便於觀察,選擇redis作為快取系統。使用方法快取的程式碼如下: class Car::CarsController < ApplicationController caches_action :index def index end end
監控方法:
開啟終端,輸入redis-cli,然後輸入monitor,可以監控redis的儲存情況。
呼叫該index方法,會產生一個key:"get""views/locahost:3003/car/cars"以後每次再去呼叫該index,你會發現redis的monitor中都是顯示如下資訊:說明快取成功,不再每次去方法中執行,而是直接從redis中去取。
1560408837.780396 [2 [::1]:54380] "get" "views/localhost:3003/car/cars" 1560408838.140465 [2 [::1]:54380] "get" "views/localhost:3003/car/cars" 1560408838.667096 [2 [::1]:54380] "get" "views/localhost:3003/car/cars"
過期時間的問題:
如果你沒有設定過期時間,那麼他的過期時間使用redis設定的過期時間。
如果想檢視過期時間,進入redis控制檯,然後選擇你使用的資料庫id,例如(查出來的時間是以秒為單位)
如果想自己設定過期時間,可以直接檢視gem 'actionpack-action_caching'這個gem的文件myMacBook-Pro redis-cli 127.0.0.1:6379>select 2 OK 127.0.0.1:6379[2]> TTL "views/localhost:3003/car/cars" (integer) 13620 127.0.0.1:6379[2]>=
片段快取
片段快取是rails中最常用的一種快取方式,主要是在頁面中進行區域性快取。在index.html.erb頁面中 <% cache 'test_index' do %> <%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %> <% end %>
這個其實和方法快取的監控的方式一樣,你會發現會生成"views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index"這樣的key,同時也能查到過期時間。
每次你去重新整理頁面,都會在redis中去請求這個key值對應的value值。
如果想自己設定過期時間為2小時,可以這樣設定<% cache 'test_index',expires_in: 2.hours do %> <%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %> <% end %>
如果你想讓這個"views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index"的key失效,你可以使用expire_fragment('views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index') ,但是在實際應用中我們無法查到這個key的具體值,所以我們可以這樣設定:
<% cache 'test_index', {skip_digest: true} do %> <%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %> <% end %>
這樣’test_index’將會被作為cache key被快取起來,如果想要使他失效,只要在對應的action裡呼叫就expire_fragment('test_index')就行,如果不加 {skip_digest: true},那麼是無法直接呼叫expire_fragment('test_index')的。
可以簡單的檢視一下生成這個片段name的原始碼:def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil) if skip_digest name else fragment_name_with_digest(name, virtual_path) end end 可以很明顯的看出,如果skip_digest是true,將直接返回頁面中寫的name。