1 前言
通過前面的一些文章我們知道,Redis的各項能力是基于記憶體實作的,相對其他的持久化存儲(如MySQL、File等,資料持久化在磁盤上),性能會高很多,這也是高速緩存的一個優勢。
但是問題來了,每一台機器記憶體終歸是有限的,即使是叢集模式,總的記憶體空間也是有限的,不能無限制的消耗。而在Redis的使用過程中,很有可能出現使用消耗超過記憶體實際大小的情況。比如以下幾種情況:
- 未設定過期時間,Redis的Key将一直存在,直至我們明确将它删除。
- 過度跟不合理的持久化(無論是RDB快照 或是 AOF日志),都會在記憶體和磁盤中反複操作,需要一定的記憶體空間進行處理。
- 不及時清理過期緩存:清理過期緩存的方式主要有以下兩種,并不是實時或者準實時,是以存在部分過期緩存依舊存在的問題。主動定期删除: Redis 預設每 1 秒運作 10 次(平均每 100 ms 執行一次),每次随機抽取部分設定過期時間的 key,檢查是否過期,若是過期就直接删除,直至過期的 key 比率低于 1/4。被動惰性删除:緩存過期并不馬上清理,當用戶端的請求查詢該 key 的時候,檢查下 key 是否過期,如果過期,則删除該 key,重新擷取。如果長時間未請求,就會有過期緩存滞留。
- 不合理不規範的使用緩存,導緻記憶體耗盡,比如:過度使用緩存,既緩存冷資料也能緩存熱資料,導緻記憶體占用過多,性能也沒有得到有效提高緩存數量過多或者單個緩存的Value體積過大緩存過期時間設定過長或者根本不設定
2 Redis記憶體淘汰政策
是以,如果放任上面的那幾種情況,記憶體終歸會滿的,Redis自身有一套比較完善的記憶體淘汰政策來專門應對這個問題,在Redis Memory占用超過我們配置的門檻值的時候觸發政策執行。
# redis.conf 配置最大記憶體空間占用為2gb,超過則執行記憶體淘汰政策
redis > CONFIG SET maxmemory 2gb
記憶體淘汰政策一共有8中,除了一種不執行淘汰政策之外,其他7種都是按照各自不一的算法對記憶體中現有的資料進行處理。
我們下面詳細來看一下這些淘汰政策,把他們分成三大類,8小類來逐一講解:
2.1 不淘汰政策
2.1.1 noeviction 不淘汰政策
noeviction指的是即使資源超過 maxmemory 限制的值也不會執行淘汰,隻是不允許建立新的緩存了。
當Redis記憶體占用達到我們上面的配置的門檻值(比如 5gb)之後,就不允許新增緩存key了,當有新的緩存要建立的時候,Redis 直接傳回error。
2.2 僅淘汰配置過期時間key
這邊僅針對配置了過期時間的資料進行淘汰
2.3.1 volatile-lru :删除最近最少使用的key
LRU(Least Recently Used)是按照最近最少使用原則來篩選資料,即最不常用的資料會被篩選出來。
如果我們的服務中有冷熱資料隔離需求,這無疑是一個比較好的辦法。可以将緩存的一些不經常使用的冷資料,而且資料size比較大的,篩選出來清理掉。而近期頻繁被使用的key就被保留下來了。
常見的場景如下:
- 電商平台的冷熱資料:比如冬季,保暖冬裝、電暖裝置的浏覽次數就會升高,而相應的冷飲、制冷裝置(冰箱、空調)的浏覽次數就會降低,那麼LRU政策下優先删除的就是最近一段時間未通路的緩存資訊。
- 外賣平台:每天的11~13點,17~19點,一定是美食外賣品種的高頻率通路時間段,而日用品、果蔬生鮮 大都會避開這個高峰期,這時如果記憶體不夠用了,那麼就會成為被優先删除的緩存類型。
2.3.2 volatile-lfu:删除通路次數最少的key(4.0 之後新增的政策)
LRU算法的不足之處在于,一個本身很少被通路的key,隻是剛剛被通路了1次,就被認為是最近有使用的熱點資料,導緻短時間内不會被淘汰。
而LFU彌補了這個不足,LFU(Least Frequently Used)淘汰政策會根據key的最近通路頻率進行淘汰,解決上面說的這個不足。
- LFU在LRU的基礎上,為每個資料增加了一個計數器,用于統計該資料的通路次數。
- 當使用LFU政策淘汰資料時,會根據資料的通路次數進行篩選,把通路次數最低的資料淘汰出記憶體。
- 如果兩個緩存資料的通路次數相同,LFU再比較這兩個key最近一次的通路時間,把通路時間更早的緩存key淘汰出記憶體。
常見的應用場景:
- 對于電商平台中的冷門的商品,電子書App中熱度較低、閱讀量較低的書籍。這種類型的緩存會優先被淘汰掉。
2.3.3 volatile-random:随機删除過期key
針對有配置過期時間,但沒有明顯的冷熱通路頻率差別,所有的查詢分布比較均衡的資料。這時候就使用 allkeys-random 政策吧,讓它随機選擇需要淘汰資料,也相對公平。
常見的使用場景有:
- 電商平台:正常時段的商品浏覽。
- 釘釘之類工具:老師無差别抽查學生的作業。
2.3.4 volatile-ttl:删除過期時間内剩餘時間最短的key
這個特性僅限于配置過期時間的場景,它是根據目前時間 跟 過期時間的差額進行由短到長的排序,較短的優先淘汰。
asc_sort(validate_time - current_time)
這種算法相對來說也不考慮緩存的通路頻率和重要程度,僅按照建立的先後進行清理,越早的緩存越早清理。
是以不具備明顯特征的業務場景都适用。
2.3.5 補充說明
業務場景有一些資料始終不需要删除,比如置頂新聞、視訊,還有我們自己置頂的weibo。為了保障它們不被清理掉,就給這些資料不設定過期時間,這樣的話 volatile類型的淘汰政策就不會影響了。但如果是 allkeys 開頭的政策依舊會影響到。
2.3 淘汰所有緩存類型的key
無論是否配置了過期時間的資料均可進行淘汰。
從微服務拆分的角度說,不同的服務類型個方向的服務進行院子隔離會比較一點。這一點設計思維在緩存上依舊适用。
我們可以将不需要過期時間的緩存資訊 和 需強制配置過期時間的緩存key分開。針對業務場景分别使用 volatile-xxx 政策 和 allkyes-xxx政策。
2.3.1 allkeys-lru:删除最近最少使用的key
保留最近有使用的key,類似volatile-lru
2.3.2 allkeys-lfu:删除通路次數最少的key
最不經常使用的,類似volatile-lfu
2.3.3 allkeys-random:随機删除過期key
無差别随機删除,volatile-random,為添加新資料騰出空間
2.4 政策指令的使用
# 擷取目前記憶體淘汰政策
redis > config get maxmemory-policy
# 擷取Redis能使用的最大記憶體大小:如果不設定最大記憶體大小或者設定最大記憶體大小為0,在64位作業系統下不限制記憶體大小,在32位作業系統下最多使用3GB記憶體。
redis > config get maxmemory
# 通過指令配置淘汰政策
redis > config set maxmemory-policy volatile-lru
# 設定Redis最大占用記憶體大小,這邊最大占用記憶體大小配置為2000M
redis > config set maxmemory 2000mb
3 總結
一張圖總結
為幫助開發者們提升面試技能、有機會入職BATJ等大廠公司,特别制作了這個專輯——這一次整體放出。
大緻内容包括了: Java 集合、JVM、多線程、并發程式設計、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大廠面試題等、等技術棧!
歡迎大家關注公衆号【Java爛豬皮】,回複【666】,擷取以上最新Java後端架構VIP學習資料以及視訊學習教程,然後一起學習,一文在手,面試我有。
每一個專欄都是大家非常關心,和非常有價值的話題,如果我的文章對你有所幫助,還請幫忙點贊、好評、轉發一下,你的支援會激勵我輸出更高品質的文章,非常感謝!