LFU & LRU-K 等常用快取淘汰演算法對比
上篇文章介紹了最常用的LRU演算法及實現,本篇總結常用快取淘汰演算法,歸總對比。
一、LFU
(Least Frequently Used):最近最低使用頻次被淘汰
實現:通過count記錄快取資料的使用次數,資料塊按照引用計數排序,計數相同則按照時間排序。
1. 新加入資料插入到佇列尾部(因為引用計數為1);
2. 佇列中的資料被訪問後,引用計數增加,佇列重新排序;
3. 當需要淘汰資料時,將已經排序的列表最後的資料塊刪除。
public int removeCache() { Iterator<CacheObject<K, V>> iterator = cacheMap.values().iterator(); int count = 0 ; long minAccessCount = Long.MAX_VALUE ; while(iterator.hasNext()){ CacheObject<K, V> cacheObject = iterator.next(); if(cacheObject.isExpired() ){ iterator.remove(); count++ ; continue ; }else{ minAccessCount = Math.min(cacheObject.accessCount , minAccessCount) ; } } if(count > 0 ) return count ; if(minAccessCount != Long.MAX_VALUE ){ iterator = cacheMap.values().iterator(); while(iterator.hasNext()){ CacheObject<K, V> cacheObject = iterator.next(); cacheObject.accessCount -= minAccessCount ; if(cacheObject.accessCount <= 0 ){ iterator.remove(); count++ ; } } } return count; }
缺點:
1、需要維護一個佇列記錄所有資料的訪問記錄,每個資料都需要維護引用計數。
2、需要記錄所有資料的訪問記錄,記憶體消耗較高
2、需要基於引用計數重排序,效能消耗較高。
優點:
1、按照頻率排序,LFU命中效率要優於LRU。
2、能避免因非熱點資料介入導致的快取命中率下降的問題。(先經過一次頻率計算了)
LFU演算法變種詳情訪問:LFU
二、LRU-K
相比LRU,LRU-K需要多維護一個佇列,用於記錄所有快取資料被訪問的歷史。只有當資料的訪問次數達到K次的時候,才將資料放入快取。當需要淘汰資料時,LRU-K會淘汰第K次訪問時間距當前時間最大的資料。
實現:優先順序佇列,演算法複雜度和代價比較高
1. 資料第一次被訪問,加入到訪問歷史列表;
2. 如果資料在訪問歷史列表裡後沒有達到K次訪問,則按照一定規則(FIFO,LRU)淘汰;
3. 當訪問歷史佇列中的資料訪問次數達到K次後,將資料索引從歷史佇列刪除,將資料移到快取佇列中,並快取此資料,快取佇列重新按照時間排序;
4. 快取資料佇列中被再次訪問後,重新排序;
5. 需要淘汰資料時,淘汰快取佇列中排在末尾的資料,即:淘汰“倒數第K次訪問離現在最久”的資料。
優點:LRU-K具有LRU的優點(熱點高頻資料命中率高,命中率比LRU要高),同時能降低“快取汙染”問題
缺點:
1、適應性差,需要大量的資料訪問才能將歷史訪問記錄清除掉。
2、歷史記錄提高記憶體消耗:由於LRU-K還需要記錄那些被訪問過、但還沒有放入快取的物件,因此記憶體消耗會比LRU要多;當資料量很大的時候,記憶體消耗會比較可觀。
3、時間排序拉高CPU消耗:LRU-K需要基於時間進行排序(可以需要淘汰時再排序,也可以即時排序),CPU消耗比LRU要高。
實際應用中LRU-2是綜合各種因素後最優的選擇,LRU-3或者更大的K值命中率會高
三、FIFO
基本佇列,不多說
四、Two queues
Two queues演算法類似於LRU-2,不同點在於2Q將LRU-2中的訪問歷史佇列(注意這不是快取資料的)改為一個FIFO快取佇列,即2Q演算法=一個是FIFO佇列,一個是LRU佇列。命中率高於LRU
實現:當資料第一次訪問時,2Q演算法將資料快取在FIFO佇列裡面,當資料第二次被訪問時,則將資料從FIFO佇列移到LRU佇列裡,兩個佇列各自按照自己的方法淘汰資料。
1. 新訪問的資料插入到FIFO佇列;
2. 如果資料在FIFO佇列中一直沒有被再次訪問,則最終按照FIFO規則淘汰;
3. 如果資料在FIFO佇列中被再次訪問,則將資料移到LRU佇列頭部;
4. 如果資料在LRU佇列再次被訪問,則將資料移到LRU佇列頭部;
5. LRU佇列淘汰末尾的資料。
五、Multi Queue
優先快取訪問次數多的資料,根據訪問頻率將資料劃分為多個佇列,不同的佇列具有不同的訪問優先順序
實現:
1. 新插入的資料放入Q0;
2. 每個佇列按照LRU管理資料;
3. 當資料的訪問次數達到一定次數,需要提升優先順序時,將資料從當前佇列刪除,加入到高一級佇列的頭部;
4. 為了防止高優先順序資料永遠不被淘汰,當資料在指定的時間裡訪問沒有被訪問時,需要降低優先順序,將資料從當前佇列刪除,加入到低一級的佇列頭部;
5. 需要淘汰資料時,從最低一級佇列開始按照LRU淘汰;每個佇列淘汰資料時,將資料從快取中刪除,將資料索引加入Q-history頭部;
6. 如果資料在Q-history中被重新訪問,則重新計算其優先順序,移到目標佇列的頭部;
7. Q-history按照LRU淘汰資料的索引。
對比點 |
對比 |
命中率 |
LRU-2 > MQ(2) > 2Q > LRU |
複雜度 |
LRU-2 > MQ(2) > 2Q > LRU |
代價 |
LRU-2 > MQ(2) > 2Q > LRU |
實際應用中需要根據業務的需求和對資料的訪問情況進行選擇,並不是命中率越高越好。例如:雖然LRU看起來命中率會低一些,且存在”快取汙染“的問題,但由於其簡單和代價小,實際應用中反而應用更多。