redis的內存淘汰算法LRU 算法方案

 LRU 算法具體步驟:

  • 新數據直接插入到列表頭部

  • 緩存數據被命中,將數據移動到列表頭部

  • 緩存已滿的時候,移除列表尾部數據。

03、LRU 算法實現

上面例子中可以看到,LRU 算法需要添加頭節點,刪除尾結點。而鏈表添加節點/刪除節點時間複雜度 O(1),非常適合當做存儲緩存數據容器。但是不能使用普通的單向鏈表,單向鏈表有幾點劣勢:

  1. 每次獲取任意節點數據,都需要從頭結點遍歷下去,這就導致獲取節點複雜度爲 O(N)。

  2. 移動中間節點到頭結點,我們需要知道中間節點前一個節點的信息,單向鏈表就不得不再次遍歷獲取信息。

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

使用散列表存儲節點,獲取節點的複雜度將會降低爲 O(1)。節點移動問題可以在節點中再增加前驅指針,記錄上一個節點信息,這樣鏈表就從單向鏈表變成了雙向鏈表。

綜上使用雙向鏈表加散列表結合體,數據結構如圖所示:


聊聊緩存淘汰算法-LRU 實現原理

LRU 算法改進方案

以下方案來源與 MySQL InnoDB LRU 改進算法

將鏈表拆分成兩部分,分爲熱數據區,與冷數據區,如圖所示。改進之後算法流程將會變成下面一樣:

聊聊緩存淘汰算法-LRU 實現原理

  1. 訪問數據如果位於熱數據區,與之前 LRU 算法一樣,移動到熱數據區的頭結點。

  2. 插入數據時,若緩存已滿,淘汰尾結點的數據。然後將數據插入冷數據區的頭結點。

  3. 處於冷數據區的數據每次被訪問需要做如下判斷:若該數據已在緩存中超過指定時間,比如說 1 s,則移動到熱數據區的頭結點。若該數據存在在時間小於指定的時間,則位置保持不變。

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

其他改進方法還有 LRU-K,2Q,LIRS 算法,感興趣同學可以自行查閱。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章