Active 支援快取儲存
一種抽象快取儲存類別。有多種快取儲存實作,各實作具有不同的附加功能。請參閱 ActiveSupport::Cache
模組下的類別,例如 ActiveSupport::Cache::MemCacheStore
。 MemCacheStore
目前是大型製作網站最受歡迎的快取儲存。
有些實作可能不支援基礎快取方法以外的所有方法,例如 fetch
、write
、read
、exist?
以及 delete
。
ActiveSupport::Cache::Store
可以儲存任何由其 coder
的 dump
和 load
方法所支援的 Ruby 物件。
cache = ActiveSupport::Cache::MemoryStore.new
cache.read('city') # => nil
cache.write('city', "Duckburgh") # => true
cache.read('city') # => "Duckburgh"
cache.write('not serializable', Proc.new {}) # => TypeError
金鑰會永遠轉換成字串且區分大小寫。當指定物件為金鑰,而且已定義 cache_key
方法時,這個方法就能呼叫來定義金鑰。否則,就會呼叫 to_param
方法。哈希和陣列也可以用來當作金鑰。這些元素將會以斜線分隔,而且會依金鑰排序 Hash
內的元素,以確保一致性。
cache.read('city') == cache.read(:city) # => true
可以快取空值。
如果您的快取是在共享基礎設施中,您可以為快取條目定義命名空間。如果已定義命名空間,它將會字首附加至每個金鑰。命名空間可以是靜態值或 Proc。如果是 Proc,每次評估各個金鑰時都會呼叫它,以便您可使用應用邏輯來取消金鑰的效度。
cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
@last_mod_time = Time.now # Invalidate the entire cache by changing namespace
- C
- D
- E
- F
- I
- K
- M
- N
- R
- S
- W
屬性
[R] | 選項 | |
[R] | 靜音 | |
[R] | 靜音? |
類別公開方法
new(options = nil) 連結
建立新的快取。
選項
:namespace
-
設定快取的命名空間。如果您的應用程式與其他應用程式共用快取,特別可以使用此選項。
:serializer
-
快取值序列化器。必須對
dump
和load
有反應。根據快取格式版本,預設序列化器的不同(當使用
Rails
時,請透過config.active_support.cache_format_version
設定)。每個格式版本的預設序列化器包含一個中繼機制,用於從任何格式版本取消序列化的值。此行為讓您可以在格式版本之間輕鬆執行遷移,而不會使整個快取失效。您也可以指定
serializer: :message_pack
來使用基於ActiveSupport::MessagePack
的預先設定序列化器。:message_pack
序列化器包含相同的序列化中繼機制,讓您可以輕鬆從(或轉換至)預設序列化器。:message_pack
序列化器可能會提升效能,但它需要msgpack
這個 gem。 :compressor
-
序列化快取值後用於壓縮的壓縮器。必須對
deflate
和inflate
有反應。預設壓縮器為
Zlib
。若要定義一個自訂壓縮器,它也會解壓縮舊的快取條目,您可以檢查壓縮值的 Zlib"\x78"
簽章碼module MyCompressor def self.deflate(dumped) # compression logic... (make sure result does not start with "\x78"!) end def self.inflate(compressed) if compressed.start_with?("\x78") Zlib.inflate(compressed) else # decompression logic... end end end ActiveSupport::Cache.lookup_store(:redis_cache_store, compressor: MyCompressor)
:coder
-
用於序列化和(選擇性)壓縮快取條目的編碼器。必須回應
dump
和load
。預設編碼器組成序列化器和壓縮器,並包含一些效能最佳化。如果您只需要覆寫序列化器或壓縮器,您應改為指定
:serializer
或:compressor
選項。如果儲存體可以直接處理快取條目,您還可以指定
coder: nil
省略序列化器、壓縮器和編碼器。例如,如果您正在使用ActiveSupport::Cache::MemoryStore
,並且可以保證快取值不會異動,您可以指定coder: nil
,以避免防止異動所產生的負擔。:coder
選項與:serializer
和:compressor
選項互斥。若同時指定,會產生ArgumentError
。
# File activesupport/lib/active_support/cache.rb, line 295 def initialize(options = nil) @options = options ? validate_options(normalize_options(options)) : {} @options[:compress] = true unless @options.key?(:compress) @options[:compress_threshold] ||= DEFAULT_COMPRESS_LIMIT @coder = @options.delete(:coder) do legacy_serializer = Cache.format_version < 7.1 && !@options[:serializer] serializer = @options.delete(:serializer) || default_serializer serializer = Cache::SerializerWithFallback[serializer] if serializer.is_a?(Symbol) compressor = @options.delete(:compressor) { Zlib } Cache::Coder.new(serializer, compressor, legacy_serializer: legacy_serializer) end @coder ||= Cache::SerializerWithFallback[:passthrough] @coder_supports_compression = @coder.respond_to?(:dump_compressed) end
實體公開方法
cleanup(options = nil) 連結
透過移除過期的條目,清理快取。
選項傳遞給底層快取實作。
部分實作可能不支援此方法。
clear(options = nil) 連結
清除整個快取。使用此方法時要小心,如果使用共用快取,這可能會影響其他程序。
選項 hash 傳遞給底層快取實作。
部分實作可能不支援此方法。
decrement(name, amount = 1, options = nil) 連結
遞減快取中的整數值。
選項傳遞給底層快取實作。
部分實作可能不支援此方法。
delete(name, options = nil) 連結
刪除快取中的條目。如果刪除條目,傳回 true
,否則傳回 false
。
選項傳遞給底層快取實作。
delete_matched(matcher, options = nil) 連結
刪除與鍵值模式相符的所有輸入項。
選項傳遞給底層快取實作。
部分實作可能不支援此方法。
delete_multi(names, options = nil) 連結
刪除快取中的多個輸入項。傳回已刪除輸入項的數量。
選項傳遞給底層快取實作。
# File activesupport/lib/active_support/cache.rb, line 689 def delete_multi(names, options = nil) return 0 if names.empty? options = merged_options(options) names.map! { |key| normalize_key(key, options) } instrument_multi(:delete_multi, names, options) do delete_multi_entries(names, **options) end end
exist?(name, options = nil) 連結
如果快取含有給定鍵值的輸入項,則傳回 true
。
選項傳遞給底層快取實作。
# File activesupport/lib/active_support/cache.rb, line 703 def exist?(name, options = nil) options = merged_options(options) key = normalize_key(name, options) instrument(:exist?, key) do |payload| entry = read_entry(key, **options, event: payload) (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false end end
fetch(name, options = nil, &block) 連結
使用給定的鍵值,從快取中擷取資料。如果快取中含有給定鍵值的資料,則傳回該資料。
如果快取中沒有此資料(快取遺漏),則傳回 nil
。不過,如果已傳入區段,則會將該區段傳遞鍵值,並在快取遺漏時執行。區段的傳回值會以給定的快取鍵值寫入快取,而且會傳回該傳回值。
cache.write('today', 'Monday')
cache.fetch('today') # => "Monday"
cache.fetch('city') # => nil
cache.fetch('city') do
'Duckburgh'
end
cache.fetch('city') # => "Duckburgh"
選項
在內部,fetch
會在快取遺漏時呼叫 read_entry
,並呼叫 write_entry
。因此,fetch
支援與 read
和 write
相同的選項。此外,fetch
支援下列選項
-
force: true
- 強制進行快取「遺漏」,意即我們會將快取值視為遺漏狀態,即使它存在。在force
為 true 時,傳遞區段是必須的,因此這樣總是會進行快取寫入作業。cache.write('today', 'Monday') cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday' cache.fetch('today', force: true) # => ArgumentError
在您呼叫其他方法來詢問是否應該強制進行快取寫入作業時,
:force
選項很有用。否則,只呼叫write
會更為明確。 -
skip_nil: true
- 避免快取 nil 結果cache.fetch('foo') { nil } cache.fetch('bar', skip_nil: true) { nil } cache.exist?('foo') # => true cache.exist?('bar') # => false
-
:race_condition_ttl
- 指定一個時間,在這個時間內,過期的值可在新的值產生時重新使用。這可以用來避免快取輸入項過期時的競爭情況,方法是避免多個處理同時重新產生相同的輸入項(也稱為狗群效應)。當處理會遇到快取輸入項的情況,而該輸入項是在不到
:race_condition_ttl
秒前過期的,它會在產生新值前將到期時間延長:race_condition_ttl
秒。在此延伸時間視窗中,在處理產生新值時,其他處理會繼續使用舊值。在第一個處理寫入新值之後,其他處理接著就會使用它。如果第一個處理在產生新值時發生錯誤,則其他處理可以在延伸時間視窗經過後,試著產生新值。
# Set all values to expire after one minute. cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1) cache.write("foo", "original value") val_1 = nil val_2 = nil p cache.read("foo") # => "original value" sleep 1 # wait until the cache expires t1 = Thread.new do # fetch does the following: # 1. gets an recent expired entry # 2. extends the expiry by 2 seconds (race_condition_ttl) # 3. regenerates the new value val_1 = cache.fetch("foo", race_condition_ttl: 2) do sleep 1 "new value 1" end end # Wait until t1 extends the expiry of the entry # but before generating the new value sleep 0.1 val_2 = cache.fetch("foo", race_condition_ttl: 2) do # This block won't be executed because t1 extended the expiry "new value 2" end t1.join p val_1 # => "new value 1" p val_2 # => "original value" p cache.fetch("foo") # => "new value 1" # The entry requires 3 seconds to expire (expires_in + race_condition_ttl) # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1 # more second to see the entry expire. sleep 1 p cache.fetch("foo") # => nil
動態選項
在某些情況下,可能有必要根據快取值動態計算選項。為支援此功能,會傳遞 ActiveSupport::Cache::WriteOptions
執行個體,做為區段的第二個引數。例如
cache.fetch("authentication-token:#{user.id}") do |key, options|
token = authenticate_to_service
options.expires_at = token.expires_at
token
end
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 444 def fetch(name, options = nil, &block) if block_given? options = merged_options(options) key = normalize_key(name, options) entry = nil unless options[:force] instrument(:read, key, options) do |payload| cached_entry = read_entry(key, **options, event: payload) entry = handle_expired_entry(cached_entry, key, options) if entry if entry.mismatched?(normalize_version(name, options)) entry = nil else begin entry.value rescue DeserializationError entry = nil end end end payload[:super_operation] = :fetch if payload payload[:hit] = !!entry if payload end end if entry get_entry_value(entry, name, options) else save_block_result_to_cache(name, key, options, &block) end elsif options && options[:force] raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block." else read(name, options) end end
fetch_multi(*names) 連結
使用給定的金鑰從快取中擷取資料。如果快取中有使用給定金鑰的資料,則會傳回該資料。否則,會針對沒有資料的每個金鑰呼叫提供的區塊,而結果會寫入快取並傳回。因此,您需要傳遞一個區塊來傳回要寫入快取的資料。如果您不希望在找不到快取時寫入快取,請使用 read_multi
。
傳回具有每個名稱資料的雜湊。例如
cache.write("bim", "bam")
cache.fetch_multi("bim", "unknown_key") do |key|
"Fallback value for key: #{key}"
end
# => { "bim" => "bam",
# "unknown_key" => "Fallback value for key: unknown_key" }
您也可以透過 options
參數指定其他選項。請參閱 fetch
以了解詳細資料。其他選項會傳遞給基礎快取實作。例如
cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
"buzz"
end
# => {"fizz"=>"buzz"}
cache.read("fizz")
# => "buzz"
sleep(6)
cache.read("fizz")
# => nil
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 595 def fetch_multi(*names) raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given? return {} if names.empty? options = names.extract_options! options = merged_options(options) keys = names.map { |name| normalize_key(name, options) } writes = {} ordered = instrument_multi :read_multi, keys, options do |payload| if options[:force] reads = {} else reads = read_multi_entries(names, **options) end ordered = names.index_with do |name| reads.fetch(name) { writes[name] = yield(name) } end writes.compact! if options[:skip_nil] payload[:hits] = reads.keys.map { |name| normalize_key(name, options) } payload[:super_operation] = :fetch_multi ordered end write_multi(writes, options) ordered end
increment(name, amount = 1, options = nil) 連結
在快取中增加整數值。
選項傳遞給底層快取實作。
部分實作可能不支援此方法。
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 731 def increment(name, amount = 1, options = nil) raise NotImplementedError.new("#{self.class.name} does not support increment") end
mute() 連結
在區塊內靜音記錄器。
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 322 def mute previous_silence, @silence = @silence, true yield ensure @silence = previous_silence end
read(name, options = nil) 連結
使用給定的金鑰從快取中讀取資料。如果快取中有使用給定金鑰的資料,則會傳回該資料。否則,會傳回 nil
。
請注意,如果資料是用 :expires_in
或 :version
選項寫入的,則在傳回資料前,這兩個條件都會套用。
選項
-
:namespace
- 替換此呼叫的儲存空間命名空間。 -
:version
- 為快取項目指定版本。如果快取版本與請求版本不符,則讀取將被視為快取遺漏。此功能用來支援可重複使用的快取金鑰。
其他選項會由特定的快取儲存空間實作處理。
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 498 def read(name, options = nil) options = merged_options(options) key = normalize_key(name, options) version = normalize_version(name, options) instrument(:read, key, options) do |payload| entry = read_entry(key, **options, event: payload) if entry if entry.expired? delete_entry(key, **options) payload[:hit] = false if payload nil elsif entry.mismatched?(version) payload[:hit] = false if payload nil else payload[:hit] = true if payload begin entry.value rescue DeserializationError payload[:hit] = false nil end end else payload[:hit] = false if payload nil end end end
read_multi(*names) 連結
一次從快取中讀取多個值。選項可以在最後一個參數中傳遞。
有些快取實作可能會最佳化此方法。
傳回將提供的名稱對應到找到值的雜湊。
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/cache.rb, line 536 def read_multi(*names) return {} if names.empty? options = names.extract_options! options = merged_options(options) keys = names.map { |name| normalize_key(name, options) } instrument_multi :read_multi, keys, options do |payload| read_multi_entries(names, **options, event: payload).tap do |results| payload[:hits] = results.keys.map { |name| normalize_key(name, options) } end end end
silence!() 連結
靜音記錄器。
write(name, value, options = nil) 連結
使用金鑰將值寫入緩存。coder
的 dump
和 load
方法必須支援這個值。
傳回 true
表示寫入成功,nil
表示與緩存後端溝通發生錯誤,或者 false
表示寫入失敗的原因不同。
預設情況下,會壓縮大小超過 1kB 的快取項目。壓縮功能讓更多資料可以使用相同的記憶體空間,降低快取驅逐頻率並提升命中率。
選項
-
compress: false
- 關閉快取項目的壓縮功能。 -
:compress_threshold
- 壓縮門檻,以位元組指定。大於此門檻的快取項目會壓縮。預設值為1.kilobyte
。 -
:expires_in
- 設定快取項目的相對到期時間,以秒指定。:expire_in
和:expired_in
是:expires_in
的別名。cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes) cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
-
:expires_at
- 設定快取項目的絕對到期時間。cache = ActiveSupport::Cache::MemoryStore.new cache.write(key, value, expires_at: Time.now.at_end_of_hour)
-
:version
- 指定快取項目的版本。從快取讀取時,如果快取版本與要求的版本不符,讀取將視為快取未命中。此功能用於支援可回收快取金鑰。
其他選項會由特定的快取儲存空間實作處理。
# File activesupport/lib/active_support/cache.rb, line 662 def write(name, value, options = nil) options = merged_options(options) key = normalize_key(name, options) instrument(:write, key, options) do entry = Entry.new(value, **options.merge(version: normalize_version(name, options))) write_entry(key, entry, **options) end end
write_multi(hash, options = nil) 連結
Cache
儲存 API,可一次寫入多個值。
# File activesupport/lib/active_support/cache.rb, line 551 def write_multi(hash, options = nil) return hash if hash.empty? options = merged_options(options) normalized_hash = hash.transform_keys { |key| normalize_key(key, options) } instrument_multi :write_multi, normalized_hash, options do |payload| entries = hash.each_with_object({}) do |(name, value), memo| memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options))) end write_multi_entries entries, **options end end
實例私人方法
key_matcher(pattern, options) 連結
將選項中定義的命名空間加入配對金鑰的樣式中。支援 delete_matched
的實作應呼叫此方法,以將配對名稱的樣式轉譯為配對帶命名空間金鑰的樣式。
# File activesupport/lib/active_support/cache.rb, line 779 def key_matcher(pattern, options) # :doc: prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace] if prefix source = pattern.source if source.start_with?("^") source = source[1, source.length] else source = ".*#{source[0, source.length]}" end Regexp.new("^#{Regexp.escape(prefix)}:#{source}", pattern.options) else pattern end end