1.數據為什么會過期?
首先,要明白redis是用來做數據緩存的,不是用來做數據存儲的(當然也可以當數據庫用),所以數據時候過期的,過期的數據就不見了,過期主要有兩種情況,
①在設置緩存數據時制定了過期時間,這樣到了過期時間數據就不見了。
②redis的數據是存放在內存中的,而內存是有限的,是不可能放過多數據的,比如只有10G的內存,想要向里面放入20G的數據,那么就注定會有10G的數據會丟失。
2.redis的過期策略是什么樣的?
redis采用了 “定期刪除+惰性刪除” 的過期策略。
①定期刪除
原理:定期刪除指的是redis默認每隔100ms就隨機抽取一些設置了過期時間的key,檢測這些key是否過期,如果過期了就將其刪掉。
為什么會選擇一部分,而不是全部:因為如果這是redis里面有大量的key都設置了過期時間,那么如果全部去檢測一遍,CPU負載就會很高,會浪費大量的時間在檢測上面,甚至直接導致redis掛掉。所有只會抽取一部分而不會全部檢查。
出現問題:這樣的話就會出現大量的已經過期的key并沒有被刪除,這就是 為什么有時候大量的key明明已經過了失效時間,但是redis的內存還是被大量占用的原因 ,為了解決這個問題,就需要 惰性刪除 這個策略了。
②惰性刪除
原理:惰性刪除不在是redis去主動刪除,而是在你要獲取某個key 的時候,redis會先去檢測一下這個key是否已經過期,如果沒有過期則返回給你,如果已經過期了,那么redis會刪除這個key,不會返回給你。
這樣兩種策略就保證了 過期的key最終一定會被刪除掉 ,但是這只是保證了最終一定會被刪除,要是定時刪除漏掉了大量過期的key,而且我們也沒有及時的去訪問這些key,那么這些key不就不會被刪除了嗎?不就會一直占著我們的內存嗎?這樣不還是會導致redis內存耗盡嗎?
由于存在這樣的問題,所以redis引入了 內存淘汰機制 來解決。
3.內存淘汰機制
內存淘汰機制就保證了在redis的內存占用過多的時候,去進行內存淘汰,也就是刪除一部分key,保證redis的內存占用率不會過高,那么它會刪除那些key呢?
redis提供了6中內存淘汰策略,我們可以去進行選擇,六中策略如下:
①noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯,無法寫入新數據,一般不采用。
②allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key,這個是最常用的。
③allkeys-random:當內存不足以容納新寫入的數據時,在鍵空間中,隨機移除key,一般也不使用。
④volatile-lru:volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key(這個一般不太合適) 。
⑤volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key 。
⑥volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。
4.手寫一個LRU算法
//基于JavaLinkedHashMap實現
public class LRUCache<K,V> extends LinkedHashMap<K,V>{
private final int CACHE_SIZE;
//保存傳遞進來的最大數據量
public LRUCache(int cacheSize){
//設置hashmap的初始大小,同時最后一個true指的是讓linkedhashmap按照訪問順序來進行排序,
//最近訪問的放在頭,最老訪問的放在尾
super((int)Math.ceil(cacheSize/0.75)+1,0.75f,true);
CACHE_SIZE = CacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest){
//當map中的數據量大于指定的緩存個數的時候,就自動刪除最老的數據。
return size() > CACHE_SIZE;
}
}