天天看點

redis 的過期政策都有哪些?記憶體淘汰機制都有哪些?

面試題

redis 的過期政策都有哪些?記憶體淘汰機制都有哪些?手寫一下 LRU 代碼實作?

面試官心理分析

如果你連這個問題都不知道,上來就懵了,回答不出來,那線上你寫代碼的時候,想當然的認為寫進 redis 的資料就一定會存在,後面導緻系統各種 bug,誰來負責?

常見的有兩個問題:

往 redis 寫入的資料怎麼沒了?

可能有同學會遇到,在生産環境的 redis 經常會丢掉一些資料,寫進去了,過一會兒可能就沒了。我的天,同學,你問這個問題就說明 redis 你就沒用對啊。redis 是緩存,你給當存儲了是吧?

啥叫緩存?用記憶體當緩存。記憶體是無限的嗎,記憶體是很寶貴而且是有限的,磁盤是廉價而且是大量的。可能一台機器就幾十個 G 的記憶體,但是可以有幾個 T 的硬碟空間。redis 主要是基于記憶體來進行高性能、高并發的讀寫操作的。

那既然記憶體是有限的,比如 redis 就隻能用 10G,你要是往裡面寫了 20G 的資料,會咋辦?當然會幹掉 10G 的資料,然後就保留 10G 的資料了。那幹掉哪些資料?保留哪些資料?當然是幹掉不常用的資料,保留常用的資料了。

資料明明過期了,怎麼還占用着記憶體?

這是由 redis 的過期政策來決定。

面試題剖析

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 記憶體淘汰機制有以下幾個:

noeviction: 當記憶體不足以容納新寫入資料時,新寫入操作會報錯,這個一般沒人用吧,實在是太惡心了。

allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)。

allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,随機移除某個 key,這個一般沒人用吧,為啥要随機,肯定是把最近最少使用的 key 給幹掉啊。

volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的 key(這個一般不太合适)。

volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,随機移除某個 key。

volatile-ttl:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,有更早過期時間的 key 優先移除。

手寫一個 LRU 算法

你可以現場手寫最原始的 LRU 算法,那個代碼量太大了,似乎不太現實。

不求自己純手工從底層開始打造出自己的 LRU,但是起碼要知道如何利用已有的 JDK 資料結構實作一個 Java 版的 LRU。

繼續閱讀