1. 程式人生 > >Rails.cache相關知識

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 首先如何設定開啟快取

  1. production上預設開啟了快取

  2. 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,例如(查出來的時間是以秒為單位)

        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]>=
    如果想自己設定過期時間,可以直接檢視gem 'actionpack-action_caching'這個gem的文件
  • 片段快取
    片段快取是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。