快取系列文章--3.快取常用更新策略對比(一致性)。
一、快取的幾種更新策略
從下面的表格看,快取的更新策略大致分為三種,本文將從一致性和維護成本兩個方面對於三種快取更新策略進行簡要說明,因為這些東西比較理論和抽象,如哪裡說得不對,歡迎拍磚。
注:
(1) 一致性:快取和真實資料來源(例如mysql, hbase, elasticsearch等等)是否存在一段時間資料的不一致。
(2) 維護成本: 開發人員的開發和維護成本。
策略 | 一致性 | 維護成本 |
LRU/LIRS/FIFO演算法剔除 | 最差 | 低 |
超時剔除 | 較差 | 較低 |
主動更新 | 強 | 高 |
二、LRU/LFU/FIFO演算法剔除
1. 使用場景:
通常用於快取使用量超過了預設的最大值時候(快取空間不夠),如何對現有的資料進行清理。例如FIFO會把最新進入快取的資料清理出去, LRU會把最近最少使用的資料清理掉。
例如:Memcache使用的是LRU,具體Memcache如何實現的,這裡就不在贅述了,網上資料多的是。
例如:Redis使用maxmemory-policy這個配置作為記憶體最大值後對於資料的更新策略。
配置名 | 含義 | 預設值 |
maxmemory | 最大可用記憶體 | 不使用該配置,也就對記憶體使用無限制 |
maxmemory-policy | 記憶體不夠時,淘汰策略 | volatile-lru |
- volatile-lru -> 用lru演算法刪除過期的鍵值
- allkeys-lru -> 用lru演算法刪除所有鍵值
- volatile-random -> 隨機刪除過期的鍵值
- allkeys-random -> 隨機刪除任何鍵值
- volatile-ttl -> 刪除最近要到期的鍵值
- noeviction -> 不刪除鍵,只返回一個錯誤
2. 常用演算法:
這裡不再贅述,常用的演算法有如下幾種:
FIFO[first in first out]
LFU[Less Frequently Used]
LRU[Least Recently used]
3. 一致性
可以想象,要清理哪些資料,不是由開發者決定(只能決定大致方向:策略演算法),資料的一致性是最差的。
4. 維護成本
這些演算法不需要開發者自己來實現,通常只需要配置最大maxmemory和對應的策略即可。
開發者只需要有這個東西,知道是什麼意思,選擇自己需要的演算法,演算法的實現是由快取伺服器實現的。
三、超時剔除
1. 使用場景:
就是我們通常做的快取資料過期時間設定,例如redis和memcache都提供了expire這樣的API,來設定K-V的過期時間。
一般來說業務可以容忍一段時間內(例如一個小時),快取資料和真實資料(例如:mysql, hbase等等)資料不一致(一般來說,快取可以提高訪問速度降低後端負載),那麼我們可以對一個數據設定一定時間的過期時間,在資料過期後,再從真實資料來源獲取資料,重新放到快取中,繼續設定過期時間。
例如: 一個視訊的描述資訊,我們可以容忍一個小時內資料不一致,但是涉及到錢的方面,如果不一致可想而知。
2. 一致性:
一段時間內(取決於過期時間)存在資料一致性問題,即快取資料和真實資料來源資料不一致。
3. 維護成本
使用者的維護成本不是很高,只需要設定expire過期時間即可(前提是你的業務允許這段時間可能發生的資料不一致)。
四、主動更新
1. 使用背景:
業務對於資料的一致性要求很高,需要在真實資料更新後,立即更新快取資料。
具體做法:例如可以利用訊息系統或者其他方式(比如資料庫觸發器,或者其他資料來源的listener機制來完成)通知快取更新。
2. 一致性:
可以想象一致性最高(幾乎接近強一致),但是有個問題:如果主動更新發生了問題,那麼這條資料很可能很長時間不會更新了(所以可以結合超時剔除一起使用,下面最佳實踐會說到)
3. 維護成本:
相當高,使用者需要自己來完成更新(需要一定量的程式碼,從某種程度上加大了系統的複雜性),需要自己檢查資料是否真的更新了之類的工作。
五、最佳實踐
其實最佳實踐就是組合使用:
1. 一般來說我們都需要配置超過最大快取後的更新策略(例如:LRU)以及最大記憶體,這樣可以保證系統可以繼續執行(例如redis可能存在OOM問題)(極端情況下除外,資料一致性要求極高)。
2. 一般來說我們需要把超時剔除和主動更新組合使用,那樣即使主動更新出了問題,也能保證過期時間後,快取就被清除了(不至於永遠都是髒資料)。