那些年我們一起追過的快取寫法 三

2022-01-17 12:49:15 字數 2557 閱讀 9801

上篇介紹了多級快取,本章詳細介紹下記憶體快取該如何設計。

閱讀目錄:

分析設計

o(1)lru實現

過期刪除策略

總結假設有個專案有比較高的併發量,要用到多級快取,如下:

在實際設計乙個記憶體快取前,需要考慮的問題:

2:記憶體容量的限制,需要控制快取數量。

3:熱點資料更新不同,需要可配置單個key過期時間。

4:良好的快取過期刪除策略。

5:快取資料結構的複雜度盡可能的低。

關於置換及命中率:採用lru演算法,因為它實現簡單,快取key命中率也很好。

lru即是:把最近最少訪問的資料給淘汰掉,經常被訪問到即是熱點資料。

關於lru資料結構:因為key優先順序提公升和key淘汰,所以需

要順序結構,網上

大多實現都採用的這種鍊錶結構。

即新資料插入到鍊錶頭部、被命中時的資料移動到頭部,

新增複雜度

o(1),移動和獲取複雜度o(n)。

有沒複雜度更低的呢? 有dictionary,複雜度為o(1),效能最好。 那如何保證快取的優先順序提公升呢?

定義個lrucache類,構造引數maxkeysize 來控制快取最大數量。

使用concurrentdictionary來作為我們的快取容器,並能保證執行緒安全。

public

class lrucache: ienumerablestring, tvalue>>

}

上面定義了 agetodiscard、currentage 這2個自增值引數,作用是

標記快取列表中各個key的新舊程度。

實現步驟如下:

每次新增key時,currentage自增並將currentage值分配給這個快取值的age,currentage一直自增。

public

void add(string

key, tvalue value)

public

class

trackvalue

}

在新增時,如超過最大數量,檢查字典裡是否有agetodiscard年齡的key,如沒有迴圈自增檢查,有則刪除、新增成功。

其agetodiscard+maxsize=

currentage ,這樣設計就能在o(1)下保證可以淘汰舊資料,而不是使用鍊錶移動。 

public

void adjust(string

key)

}

獲取key的時候表示它又被人訪問,將最新的currentage賦值給它,增加它的年齡:

public tvalue get(string

key)

return

value.value;

}

大多數情況下,lru演算法對熱點資料命中率是很高的。 但如果突然大量偶發性的資料訪問,會讓記憶體中存放大量冷資料,也即是快取汙染。

會引起lru無法命中熱點資料,導致快取系統命中率急劇下降,也可以使用lru-k、2q、mq等變種演算法來提高命中率。

通過設定最大過期時間來盡量避免冷資料常駐記憶體。

多數情況每個資料快取的時間要求不一致的,所以需要再增加單個key的過期時間字段。

private

timespan maxtime;

public lrucache(int

maxkeysize,timespan maxexpiretime){}

//trackvalue增加建立時間和過期時間

public

readonly

datetime createtime;

public

readonly timespan expiretime;

關於key過期刪除,最好的方式是使用定時刪除,這樣可以最快的釋放被占用的記憶體,但很明顯大量的定時器對cpu來說是非常不友好的。

所以需要採用惰性刪除、在獲取key的時檢查是否過期,過期直接刪除。

public tuplebool> checkexpire(string

key)

}return tuple.create(result, true

); }

惰性刪除雖然效能最好,但對於冷資料來說還是沒解決快取汙染的問題,所以還需增加個定期清理和惰性刪除配合使用。

比如單開個執行緒每5分鐘去遍歷檢查key是否過期,這個時間策略是可配置的,如果快取數量較多可分批遍歷檢查。

public

void

inspection()

}

惰性刪除配合定期刪除基本上能滿足絕大多數要求了。

如果繼續完善下去就是記憶體資料庫的雛形,類似redis,比如增加刪除key的通知**,支援更多的資料型別儲存。

系列目錄:

那些年我們一起追過的快取寫法(一)

那些年我們一起追過的快取寫法(二)

那些年我們一起追過的快取寫法(三) 

那些年我們一起追過的快取寫法 一

本篇主要介紹下樓主平常專案中,快取使用經驗和遇到過的問題。基本寫法 快取雪崩 全域性鎖,例項鎖 字串鎖 快取穿透 再談快取雪崩 總結為了方便演示,這裡使用runtime.cache做快取容器,並定義個簡單操作類。如下 public class cachehelper public static vo...

那些年我們一起追過的Shell Script

原本這是自己在幾個月前為公司的乙個分享活動寫的乙個投影片,今天趁大腦負荷比較小,把這個話題拿到blog上面來分享一下。從知道shell算起至今也就幾個年頭而已,如今勉強算是入門了。對某乙個新事物的掌握總是乙個循序漸近的過程,只是根據不一樣事物的特點,其學習的曲線也不盡一致。shell script算...

那些年我們一起追過的流量

前一段的熱播電影 那些年我們一起追過的女孩 很多人討論問什麼最後男女主角沒有在一起,這個麼仁者見仁,智者見智。我借這個東風,聊一聊那些年我們追過的流量,分析一下問什麼客戶不願意和自己 在一起。這些都是筆者以前做過的和看到的例子。1.關於程式設計客棧問答平台 搜搜問問 天涯問答等 以dtaye知道為例...