聊聊快取淘汰演算法 LRU 實現原理

2021-09-29 03:15:13 字數 3131 閱讀 8175

我們常用快取提公升資料查詢速度,由於快取容量有限,當快取容量到達上限,就需要刪除部分資料挪出空間,這樣新資料才可以新增進來。快取資料不能隨機刪除,一般情況下我們需要根據某種演算法刪除快取資料。常用淘汰演算法有 lru,lfu,fifo,這篇文章我們聊聊 lru 演算法。

lru是 least recently used 的縮寫,這種演算法認為最近使用的資料是熱門資料,下一次很大概率將會再次被使用。而最近很少被使用的資料,很大概率下一次不再用到。當快取容量的滿時候,優先淘汰最近很少使用的資料。

假設現在快取內部資料如圖所示:

這裡我們將列表第乙個節點稱為頭結點,最後乙個節點為尾結點。

當呼叫快取獲取 key=1 的資料,lru 演算法需要將 1 這個節點移動到頭結點,其餘節點不變,如圖所示。

然後我們插入乙個 key=8 節點,此時快取容量到達上限,所以加入之前需要先刪除資料。由於每次查詢都會將資料移動到頭結點,未被查詢的資料就將會下沉到尾部節點,尾部的資料就可以認為是最少被訪問的資料,所以刪除尾結點的資料。

然後我們直接將資料新增到頭結點。

這裡總結一下 lru 演算法具體步驟:

上面例子中可以看到,lru 演算法需要新增頭節點,刪除尾結點。而鍊錶新增節點/刪除節點時間複雜度 o(1),非常適合當做儲存快取資料容器。但是不能使用普通的單向鍊錶,單向鍊錶有幾點劣勢:

每次獲取任意節點資料,都需要從頭結點遍歷下去,這就導致獲取節點複雜度為 o(n)。

移動中間節點到頭結點,我們需要知道中間節點前乙個節點的資訊,單向鍊錶就不得不再次遍歷獲取資訊。

針對以上問題,可以結合其他資料結構解決。

使用雜湊表儲存節點,獲取節點的複雜度將會降低為 o(1)。節點移動問題可以在節點中再增加前驅指標,記錄上乙個節點資訊,這樣鍊錶就從單向鍊錶變成了雙向鍊錶。

綜上使用雙向鍊錶加雜湊表結合體,資料結構如圖所示:

在雙向鍊錶中特意增加兩個『哨兵』節點,不用來儲存任何資料。使用哨兵節點,增加/刪除節點的時候就可以不用考慮邊界節點不存在情況,簡化程式設計難度,降低**複雜度。

lru 演算法實現**如下,為了簡化 key ,val 都認為 int 型別。

public class lrucache 

/*** 如果節點不存在,返回 -1.如果存在,將節點移動到頭結點,並返回節點的資料。

** @param key

* @return

*/public int get(int key)

// 存在移動節點

movetohead(node);

return node.value;

}/**

* 將節點加入到頭結點,如果容量已滿,將會刪除尾結點

** @param key

* @param value

*/public void put(int key, int value)

// 不存在。先加進去,再移除尾結點

// 此時容量已滿 刪除尾結點

if (size == capacity)

// 加入頭結點

entry newnode = new entry();

newnode.key = key;

newnode.value = value;

addnode(newnode);

cache.put(key, newnode);

size ;

}private void movetohead(entry node)

private void addnode(entry node)

private void deletenode(entry node)

public static class entry

public entry()

}private void initlinkedlist()

public static void main(string args)

}

快取命中率是快取系統的非常重要指標,如果快取系統的快取命中率過低,將會導致查詢回流到資料庫,導致資料庫的壓力公升高。

結合以上分析 lru 演算法優缺點。

lru 演算法優勢在於演算法實現難度不大,對於對於熱點資料, lru 效率會很好。

lru 演算法劣勢在於對於偶發的批量操作,比如說批量查詢歷史資料,就有可能使快取中熱門資料被這些歷史資料替換,造成快取汙染,導致快取命中率下降,減慢了正常資料查詢。

以下方案**與 mysql innodb lru 改進演算法

將鍊錶拆分成兩部分,分為熱資料區,與冷資料區,如圖所示。

改進之後演算法流程將會變成下面一樣:

訪問資料如果位於熱資料區,與之前 lru 演算法一樣,移動到熱資料區的頭結點。

插入資料時,若快取已滿,淘汰尾結點的資料。然後將資料插入冷資料區的頭結點。

處於冷資料區的資料每次被訪問需要做如下判斷:

對於偶發的批量查詢,資料僅僅只會落入冷資料區,然後很快就會被淘汰出去。熱門資料區的資料將不會受到影響,這樣就解決了 lru 演算法快取命中率下降的問題。

其他改進方法還有 lru-k,2q,lirs 演算法,感興趣同學可以自行查閱。

快取淘汰演算法 LRU

1.lru 1.1.原理 lru least recently used,最近最少使用 演算法根據資料的歷史訪問記錄來進行淘汰資料,其核心思想是 如果資料最近被訪問過,那麼將來被訪問的機率也更高 1.2.實現 最常見的實現是使用乙個鍊錶儲存快取資料,詳細演算法實現如下 1.新資料插入到鍊錶頭部 2....

LRU 快取淘汰演算法

1.介紹 lru是leastrecentlyused近期最少使用演算法。記憶體管理的一種頁面置換演算法,對於在記憶體中但又不用的資料塊 記憶體塊 叫做lru,oracle會根據哪些資料屬於lru而將其移出記憶體而騰出空間來載入另外的資料。lru least recently used,最近最少使用 ...

LRU快取淘汰演算法

這是乙個什麼演算法?這是乙個可以處理程式過多的情況下該刪除哪乙個程式的演算法策略。它是根據最近使用時間來進行確定的,通常刪除的是最後乙個節點。那麼這個演算法會涉及什麼樣的資料結構?這個演算法涉及了hashmap和雙向鍊錶的資料結構,通過這兩個結構的配合可以通過map來快速定位訪問節點,通過雙向鍊錶來...