Redis LFU與LRU內部實現原理原始碼分析

2021-09-09 07:34:05 字數 2934 閱讀 3984

1、lru模式有效控制記憶體的大小,將冷資料從記憶體中淘汰出去,在redis裡引入乙個新的淘汰形式lfu                                     1)lfu全稱是least frequently used 表示按最近的訪問頻率進行淘汰,更加準確的判斷乙個key別訪問的熱度

2、redis物件的熱度

redis中所有物件結構頭中都有乙個24bit欄位,這個字段用來記錄物件的熱度

// redis

的物件頭

typedefstructredisobjectrobj;

3、lru模式

1)lru欄位儲存的是redis時鐘server.lruclock,預設是unix時間竄對2^24取模的結果,當某個 key 被訪問一次,它的物件頭的 lru 字段值就會被更新為server.lruclock。

2)redis的時鐘值是每公釐奧更新一次,可以在定時任務servercron裡設定

3)如果server.lruclock沒有折返 (對 2^24 取模),它就是一直遞增的,這意味著物件的 lru 字段不會超過server.lruclock的值。如果超過了,說明server.lruclock折返了。通過這個邏輯就可以精準計算出物件多長時間沒有被訪問——物件的空閒時間。

4)計算物件空閒時間

unsigned long long estimateobjectidletime(robj *o) else

}4、lfu模式

1)在該模式下,lru欄位用來儲存來個值即16個bit的ldt(last decrement time)和8bit的logc(logistic counter)。logc用來儲存訪問頻次,最大能整數值為255,儲存頻次肯定不夠,所有這8個bit只是用來儲存頻次的對數值,而且該值還隨時間在衰減,如果該值比較小,那麼很容易被**。為了確保新建立的物件不被**,新物件的8個bit會初始化為乙個大雨零的值,預設是5

2)ldt用來儲存上一次logc的更新時間,它取得是分鐘時間戳對2^16進行取模,

// nowinminutes

// server.unixtime 為 redis 快取的系統時間戳

unsigned long lfugettimeinminutes(void)

// idle_in_minutes

unsigned long lfutimeelapsed(unsigned long ldt)

3)ldt的值和lru模式的lru字段值不同的是ldt不是在物件被訪問時更新,他在redis的淘汰邏輯進行時進行更新,淘汰邏輯只會是在記憶體達到maxmemory設定時才促發。沒次淘汰的策略是採用隨機策略,挑選若干個key,更新這個key的熱度,淘汰掉熱度最低的key。

ldt更新的同時會衰減logc的值,衰減的演算法是將現有的logc值減去物件的空閒時間廚藝乙個衰減係數,預設的衰減西戎lfu_decay_time是1,如果這個值大於1,就會衰減比較慢,等於0就是不衰減。

// 衰減

logc

unsignedlonglfudecrandreturn(robj *o)、

4)logc的更新和lru模式的lru欄位一樣,都會在key沒次被訪問的時候更新,只不過他的更新不是簡單的+1,而是採用概率發進行遞增,因為logc儲存的是訪問計數的對數值,不能直接+1

/* logarithmically increment a counter. the greater is the current counter value

* the less likely is that it gets really implemented. saturate it at 255. */

// 對數遞增計數值

uint8_tlfulogincr(uint8_tcounter)

5、redis緩衝時間戳

redis不能沒次需要系統時間時,都呼叫一次系統獲取時間,因為這樣的呼叫對於單執行緒的redis來講,是比較費時間的,redis是承受不起,所有它需要對時間進行緩衝,獲取時間就直接從緩衝中拿

6、redis使用原子操作獲取lruclock原因

unsignedintlru_clock(void)

else

returnlruclock; }

因為 redis 實際上並不是單執行緒,它背後還有幾個非同步執行緒也在默默工作。這幾個執行緒也要訪問 redis 時鐘,所以 lruclock 欄位是需要支援多執行緒讀寫的。使用 atomic 讀寫能保證多執行緒 lruclock 資料的一致性。

7、開啟lfu模式

1)redis4.0對淘汰策略配置引數maxmemory-policy增加了2個選項,分別是volatile-lfu和allkeys-lfu,根據字面含義都可以看出,前者是對帶過期時間key進行lfu淘汰,後者的引數對所有的key進行lfu淘汰演算法

> config

setmaxmemory-policy allkeys-lfu

ok >

setcodehole yeahyeahyeah

ok //

獲取計數值,初始化為

lfu_init_val=5

> object freq codehole

(integer

) 5 > get codehole  //

訪問一次

"yeahyeahyeah"

// 計數值增加了

> object freq codehole  //get lfu

計數值 (

integer

) 6

LRU 與 LFU 演算法

lru是最近最少使用頁面置換演算法 least recently used 也就是首先淘汰最長時間未被使用的頁面 lfu是最近最不常用頁面置換演算法 least frequently used 也就是淘汰一定時期內被訪問次數最少的頁 比如,第二種方法的時期t為10分鐘,如果每分鐘進行一次調頁,主存塊...

LFU與LRU的不同

lru和lfu是不同的 lru是最近最少使用頁面置換演算法 least recently used 也就是首先淘汰最長時間未被使用的頁面 lfu是最近最不常用頁面置換演算法 least frequently used 也就是淘汰一定時期內被訪問次數最少的頁 比如,第二種方法的時期t為10分鐘,如果每...

Memcache記憶體機制與LRU

memcache的記憶體分配機制 memcache程序會預先分配一部分記憶體給slab,給slab分配的記憶體也叫page page的預設大小是1m 每個page下面會有若干個chunk chunk預設大小96b 而資料就會封裝成item儲存在chunk裡面,若干個大小相同的chunk稱為slab ...