帶你搞懂 Redis 中的兩個策略

面試的時候問到候選人 Redis 相關(guān)問題時,發(fā)現(xiàn)一個現(xiàn)象:一部分候選人分不清 Redis 的「鍵過期策略」和「內(nèi)存淘汰策略」。今天就來說一說這老哥倆。
簡單來說,過期策略就是當 key 到了指定的過期時間后,Redis 是用什么方式將其刪除的;而淘汰策略指的是當內(nèi)存不夠用時,Redis 如何處理。
過期策略
Redis 的鍵過期方式有兩種:被動和主動。
被動方式:當客戶端嘗試訪問某個過期 key 時,Redis 發(fā)現(xiàn)該 key 已過期,將其刪除。
主動方式:為每個設(shè)置了過期時間的 key 設(shè)置一個定時器,當?shù)竭_過期時間時將 key 刪除。
被動方式的問題很明顯,可能有些 key 很久不會被訪問,甚至永遠都不會被訪問,浪費內(nèi)存資源。
主動方式也有問題,需要不斷的去查看 key 是否已經(jīng)過期,過于消耗 CPU 資源。
還有一種定期刪除的方式,比如 30s 對設(shè)置過期時間的 key 進行一次掃描,并刪除那些已經(jīng)過期的 key。這種方式看起來是結(jié)合前兩者的優(yōu)勢,但是它還是過于粗暴。
那么,Redis 到底是如何處理過期 key 的呢?答案是,被動 + 優(yōu)化版的定期刪除。被動已經(jīng)說過了,下面看看 Redis 是怎么優(yōu)化定期刪除的。
Redis 是如何做的:
隨機選擇 20 個設(shè)置帶有過期時間的 key
刪除其中已經(jīng)到達過期時間的 key
如果 20 個被選 key 中有超過 1/4(5 個)已經(jīng)過期,則重復(fù)步驟 1,直到過期 key 低于 1/4
以上步驟的執(zhí)行頻率為每秒 10 次。
Redis 通過這種被動 + 優(yōu)化版定期刪除的方式使得內(nèi)存和 CPU 資源的占用達到一個平衡狀態(tài),既不會讓無效 key 占用過多內(nèi)存,又沒有過多的消耗 CPU 去做掃描工作。
過期精度
在 Redis 2.4 及以前版本,過期時間可能不是十分準確,有 1 秒以內(nèi)的誤差。
從 Redis 2.6 起,過期時間誤差縮小到 1 毫秒以內(nèi)。
淘汰策略
Redis 支持以下內(nèi)存淘汰策略:
noeviction
allkeys-lru
allkeys-random
volatile-lru
volatile-random
volatile-ttl
allkeys 代表針對所有 key,volatile 代表只針對帶過期時間的 key
noeviction:當內(nèi)存不夠用時,客戶端嘗試執(zhí)行可能需要使用更多內(nèi)存的命令(除 del 和幾個例外之外寫命令)時,返回錯誤。
lru:刪除最近最少使用的 key,為新數(shù)據(jù)騰出空間。
random:隨機刪除 key,為新數(shù)據(jù)騰出空間。
ttl:刪除剩余壽命(TTL,Time To Live)最短的 key,為新數(shù)據(jù)騰出空間。
需要注意的是,volatile-lru、volatile-random、volatile-ttl 策略下,如果找不符合條件(比如沒有帶過期時間的 key)的 key,那么處理方式基本上就是按照 noeviction 來進行。
淘汰策略最佳實踐:
當你希望 key 呈冪律分布(類似二八原則,20% 的 key 承接了 80% 的訪問)時,推薦使用 allkeys-lru。
如果你對 key 的訪問比較平均,屬于雨露均沾的類型,那么推薦使用 allkeys-random。
如果你的 key 大部分都是帶過期時間的,那么推薦使用 volatile-ttl。
對比
過期策略
對象:帶過期時間的 key
解決問題:key 到達過期時間以后,如何處理
淘汰策略
對象:所有 key(也可以只針對 expire key)
解決問題:內(nèi)存不夠用以后,怎么辦
雖然看起來很相似,但兩者干的不是一回事,它們之間沒有什么直接的關(guān)系,也不會互相影響。
