別再問我Redis內存滿了該怎麼辦了

概述

Redis的文章,我以前寫過一篇關於「Redis的緩存的三大問題」,累計閱讀也快800了,對於還只有3k左右的粉絲量,可以達到這個閱讀量,已是比較難了。web

這說明那篇文章寫的還過得去,收到不少人的閱讀確定,感興趣的看一下[看完這篇Redis緩存三大問題,保你能和麪試官互扯。]。面試

「三大緩存問題」只是Redis的其中的一小部分的知識點,想要深刻學習Redis還要學習比較多的知識點。redis

那麼今天就帶來了一個面試常問的一個問題:「假如你的Redis內存滿了怎麼辦?」 長期的把Redis做爲緩存使用,總有一天會存滿的時候對吧。算法

這個面試題不慌呀,在Redis中有配置參數maxmemory能夠「設置Redis內存的大小」緩存

在Redis的配置文件redis.conf文件中,配置maxmemory的大小參數以下所示:微信

實際生產中確定不是100mb的大小哈,不要給誤導了,這裏我只是讓你們認識這個參數,通常小的公司都是設置爲3G左右的大小。dom

除了在配置文件中配置生效外,還能夠經過命令行參數的形式,進行配置,具體的配置命令行以下所示:編輯器

//獲取maxmemory配置參數的大小
127.0.0.1:6379> config get maxmemory
//設置maxmemory參數爲100mb
127.0.0.1:6379> config set maxmemory 100mb

假若實際的存儲中超出了Redis的配置參數的大小時,Redis中有「淘汰策略」,把「須要淘汰的key給淘汰掉,整理出乾淨的一塊內存給新的key值使用」學習

接下來咱們就詳細的聊一聊Redis中的淘汰策略,而且深刻的理解每一個淘汰策略的原理和應用的場景。flex

淘汰策略

Redis提供了「6種的淘汰策略」,其中默認的是noeviction,這6種淘汰策略以下:

  1. noeviction( 「默認策略」):如果內存的大小達到閥值的時候,全部申請內存的指令都會報錯。
  2. allkeys-lru:全部key都是使用 「LRU算法」進行淘汰。
  3. volatile-lru:全部 「設置了過時時間的key使用LRU算法」進行淘汰。
  4. allkeys-random:全部的key使用 「隨機淘汰」的方式進行淘汰。
  5. volatile-random:全部 「設置了過時時間的key使用隨機淘汰」的方式進行淘汰。
  6. volatile-ttl:全部設置了過時時間的key 「根據過時時間進行淘汰,越早過時就越快被淘汰」

假如在Redis中的數據有「一部分是熱點數據,而剩下的數據是冷門數據」,或者「咱們不太清楚咱們應用的緩存訪問分佈情況」,這時可使用allkeys-lru

假如全部的數據訪問的頻率大概同樣,就可使用allkeys-random的淘汰策略。

假如要配置具體的淘汰策略,能夠在redis.conf配置文件中配置,具體配置以下所示:

這隻須要把註釋給打開就能夠,而且配置指定的策略方式,另外一種的配置方式就是命令的方式進行配置,具體的執行命令以下所示:

// 獲取maxmemory-policy配置
127.0.0.1:6379> config get maxmemory-policy
// 設置maxmemory-policy配置爲allkeys-lru
127.0.0.1:6379> config set maxmemory-policy allkeys-lru

在介紹6種的淘汰策略方式的時候,說到了LRU算法,「那麼什麼是LRU算法呢?」

LRU算法

LRU(Least Recently Used)即表示最近最少使用,也就是在最近的時間內最少被訪問的key,算法根據數據的歷史訪問記錄來進行淘汰數據。

它的核心的思想就是:「假如一個key值在最近不多被使用到,那麼在未來也不多會被訪問」

實際上Redis實現的LRU並非真正的LRU算法,也就是名義上咱們使用LRU算法淘汰鍵,可是實際上被淘汰的鍵並不必定是真正的最久沒用的。

Redis使用的是近似的LRU算法,「經過隨機採集法淘汰key,每次都會隨機選出5個key,而後淘汰裏面最近最少使用的key」

這裏的5個key只是默認的個數,具體的個數也能夠在配置文件中進行配置,在配置文件中的配置以下圖所示:

當近似LRU算法取值越大的時候就會越接近真實的LRU算法,能夠這樣理解,由於「取值越大那麼獲取的數據就越全,淘汰中的數據的就越接近最近最少使用的數據」

那麼爲了實現根據時間實現LRU算法,Redis必須爲每一個key中額外的增長一個內存空間用於存儲每一個key的時間,大小是3字節。

在Redis 3.0中對近似的LRU算法作了一些優化,Redis中會維護大小是16的一個候選池的內存。

當第一次隨機選取的採樣數據,數據都會被放進候選池中,而且候選池中的數據會根據時間進行排序。

當第二次之後選取的數據,只有「小於候選池內的最小時間」的纔會被放進候選池中。

當某一時刻候選池的數據滿了,那麼時間最大的key就會被擠出候選池。當執行淘汰時,直接從候選池中選取最近訪問時間最小的key進行淘汰。

這樣作的目的就是選取出最近似符合最近最少被訪問的key值,可以正確的淘汰key值,由於隨機選取的樣本中的最小時間可能不是真正意義上的最小時間。

可是LRU算法有一個弊端:就是假如一個key值在之前都沒有被訪問到,然而最近一次被訪問到了,那麼就會認爲它是熱點數據,不會被淘汰。

然而有些數據之前常常被訪問到,只是最近的時間內沒有被訪問到,這樣就致使這些數據極可能被淘汰掉,這樣一來就會出現誤判而淘汰熱點數據。

因而在Redis 4.0的時候除了LRU算法,新加了一種LFU算法,「那麼什麼是LFU算法算法呢?」

LFU算法

LFU(Least Frequently Used)即表示最近頻繁被使用,也就是最近的時間段內,頻繁被訪問的key,它以最近的時間段的被訪問次數的頻率做爲一種判斷標準。

它的核心思想就是:根據key最近被訪問的頻率進行淘汰,比較少被訪問的key優先淘汰,反之則優先保留。

LFU算法反映了一個key的熱度狀況,不會由於LRU算法的偶爾一次被訪問被認爲是熱點數據。

在LFU算法中支持volatile-lfu策略和allkeys-lfu策略。

以上介紹了Redis的6種淘汰策略,這6種淘汰策略旨在告訴咱們怎麼作,可是何時作?這個還沒說,下面咱們就來詳細的瞭解Redis何時執行淘汰策略。

刪除過時鍵策略

在Redis中有三種刪除的操做此策略,分別是:

  1. 「定時刪除」:建立一個定時器,定時的執行對key的刪除操做。
  2. 「惰性刪除」:每次只有再訪問key的時候,纔會檢查key的過時時間,如果已通過期了就執行刪除。
  3. 「按期刪除」:每隔一段時間,就會檢查刪除掉過時的key。

「定時刪除」對於「內存來講是友好的」,定時清理出乾淨的空間,可是對於「cpu來講並非友好的」,程序須要維護一個定時器,這就會佔用cpu資源。

「惰性的刪除」對於「cpu來講是友好的」,cpu不須要維護其它額外的操做,可是對於「內存來講是不友好的」,由於要是有些key一直沒有被訪問到,就會一直佔用着內存。

按期刪除是上面兩種方案的折中方案**,每隔一段時間刪除過時的key,也就是根據具體的業務,合理的取一個時間按期的刪除key**。

經過「最合理控制刪除的時間間隔」來刪除key,減「少對cpu的資源的佔用消耗」,使刪除操做合理化。

RDB和AOF 的淘汰處理

在Redis中持久化的方式有兩種RDBAOF,具體這兩種詳細的持久化介紹,能夠參考這一篇文章[面試造飛機系列:面對Redis持久化連環Call,你還頂得住嗎?]。

在RDB中是以快照的形式獲取內存中某一時間點的數據副本,在建立RDB文件的時候能夠經過savebgsave命令執行建立RDB文件。

「這兩個命令都不會把過時的key保存到RDB文件中」,這樣也能達到刪除過時key的效果。

當在啓動Redis載入RDB文件的時候,Master不會把過時的key載入,而Slave會把過時的key載入。

在AOF模式下,Redis提供了Rewite的優化措施,執行的命令分別是REWRITEAOFBGREWRITEAOF「這兩個命令都不會把過時的key寫入到AOF文件中,也能刪除過時key」

【推薦閱讀】

[1] 面試官最想要的synchronized,你值得擁有

[2] 面試造飛機系列:volatile面試的連環追擊,你還好嗎?

[3] 面試造飛機系列:面對Redis持久化連環Call,你還頂得住嗎?

 [4] 【源碼篇】深刻Lock鎖底層原理實現,手寫一個可重入鎖

本文分享自微信公衆號 - 非科班的科班(LDCldc123095)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索