本文由 yanglbme 首發於 GitHub 技術社區 Doocs,目前 stars 已超 30k。
項目地址:github.com/doocs/advan…java
redis 的過時策略都有哪些?內存淘汰機制都有哪些?手寫一下 LRU 代碼實現?git
若是你連這個問題都不知道,上來就懵了,回答不出來,那線上你寫代碼的時候,想固然的認爲寫進 redis 的數據就必定會存在,後面致使系統各類 bug,誰來負責?github
常見的有兩個問題:面試
可能有同窗會遇到,在生產環境的 redis 常常會丟掉一些數據,寫進去了,過一下子可能就沒了。個人天,同窗,你問這個問題就說明 redis 你就沒用對啊。redis 是緩存,你給當存儲了是吧?redis
啥叫緩存?用內存當緩存。內存是無限的嗎,內存是很寶貴並且是有限的,磁盤是廉價並且是大量的。可能一臺機器就幾十個 G 的內存,可是能夠有幾個 T 的硬盤空間。redis 主要是基於內存來進行高性能、高併發的讀寫操做的。算法
那既然內存是有限的,好比 redis 就只能用 10G,你要是往裏面寫了 20G 的數據,會咋辦?固然會幹掉 10G 的數據,而後就保留 10G 的數據了。那幹掉哪些數據?保留哪些數據?固然是幹掉不經常使用的數據,保留經常使用的數據了。緩存
這是由 redis 的過時策略來決定。微信
redis 過時策略是:按期刪除+惰性刪除。數據結構
所謂按期刪除,指的是 redis 默認是每隔 100ms 就隨機抽取一些設置了過時時間的 key,檢查其是否過時,若是過時就刪除。併發
假設 redis 裏放了 10w 個 key,都設置了過時時間,你每隔幾百毫秒,就檢查 10w 個 key,那 redis 基本上就死了,cpu 負載會很高的,消耗在你的檢查過時 key 上了。注意,這裏可不是每隔 100ms 就遍歷全部的設置過時時間的 key,那樣就是一場性能上的災難。實際上 redis 是每隔 100ms 隨機抽取一些 key 來檢查和刪除的。
可是問題是,按期刪除可能會致使不少過時 key 到了時間並無被刪除掉,那咋整呢?因此就是惰性刪除了。這就是說,在你獲取某個 key 的時候,redis 會檢查一下 ,這個 key 若是設置了過時時間那麼是否過時了?若是過時了此時就會刪除,不會給你返回任何東西。
獲取 key 的時候,若是此時 key 已通過期,就刪除,不會返回任何東西。
可是實際上這仍是有問題的,若是按期刪除漏掉了不少過時 key,而後你也沒及時去查,也就沒走惰性刪除,此時會怎麼樣?若是大量過時 key 堆積在內存裏,致使 redis 內存塊耗盡了,咋整?
答案是:走內存淘汰機制。
redis 內存淘汰機制有如下幾個:
你能夠現場手寫最原始的 LRU 算法,那個代碼量太大了,彷佛不太現實。
不求本身純手工從底層開始打造出本身的 LRU,可是起碼要知道如何利用已有的 JDK 數據結構實現一個 Java 版的 LRU。
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int CACHE_SIZE;
/** * 傳遞進來最多能緩存多少數據 * * @param cacheSize 緩存大小 */
public LRUCache(int cacheSize) {
// true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// 當 map中的數據量大於指定的緩存個數的時候,就自動刪除最老的數據。
return size() > CACHE_SIZE;
}
}
複製代碼
歡迎關注個人微信公衆號「Doocs開源社區」,原創技術文章第一時間推送。