Redis 內存淘汰機制詳解

一般來說,緩存的容量是小於數據總量的,所以,當緩存數據越來越多,Redis 不可避免的會被寫滿,這時候就涉及到 Redis 的內存淘汰機制了。我們需要選定某種策略將 “不重要” 的數據從 Redis 中清除,爲新的數據騰出空間。

配置 Redis 內存大小

我們應該爲 Redis 設置多大的內存容量呢?

根據 “八二原理 “,即 80% 的請求訪問了 20% 的數據,因此如果按照這個原理來配置,將 Redis 內存大小設置爲數據總量的 20%,就有可能攔截到 80% 的請求。當然,只是有可能,對於不同的業務場景需要進行不同的配置,一般建議把緩存容量設置爲總數據量的 15% 到 30%,兼顧訪問性能和內存空間開銷。

配置方式(以 5GB 爲例,如果不帶單位則默認單位是字節):

config set maxmemory 5gb

config get maxmemory

Redis 的內存淘汰策略

在 Redis 4.0 版本之前有 6 種策略,4.0 增加了 2 種,主要新增了 LFU 算法。

下圖爲 Redis 6.2.0 版本的配置文件:

其中,默認的淘汰策略是 noevition,也就是不淘汰

我們可以對 8 種淘汰策略可以分爲兩大類:

noevition,此策略不會對緩存的數據進行淘汰,當內存不夠了就會報錯,因此,如果真實數據集大小大於緩存容量,就不要使用此策略了。

以 volatile 開頭的策略只針對設置了過期時間的數據,即使緩存沒有被寫滿,如果數據過期也會被刪除。

以 allkeys 開頭的策略是針對所有數據的,如果數據被選中了,即使過期時間沒到,也會被刪除。當然,如果它的過期時間到了但未被策略選中,同樣會被刪除。

那麼我們如何配置過期策略呢?

config set maxmemory-policy allkeys-lru

LRU 算法

首先簡單介紹一下 LRU 算法:

LRU 全稱是 Least Recently Used,即最近最少使用,會將最不常用的數據篩選出來,保留最近頻繁使用的數據。

LRU 會把所有數據組成一個鏈表,鏈表頭部稱爲 MRU,代表最近最常使用的數據;尾部稱爲 LRU 代表最近最不常使用的數據;

下圖是一個簡單的例子:

但是,如果直接在 Redis 中使用 LRU 算法也會有一些問題:

LRU 算法在實現過程中使用鏈表管理所有緩存的數據,這會給 Redis 帶來額外的開銷,而且,當有數據訪問時就會有鏈表移動操作,進而降低 Redis 的性能。

於是,Redis 對 LRU 的實現進行了一些改變:

LFU 算法

LFU 全稱 Least Frequently Used,即最不經常使用策略,它是基於數據訪問次數來淘汰數據的,在 Redis 4.0 時添加進來。它在 LRU 策略基礎上,爲每個數據增加了一個計數器,來統計這個數據的訪問次數。

前面說到,LRU 使用了 RedisObject 中的 lru 字段記錄時間戳,lru 是 24bit 的,LFU 將 lru 拆分爲兩部分:

爲什麼 Redis 有了 LRU 還需要 LFU 呢?

在一些場景下,有些數據被訪問的次數非常少,甚至只會被訪問一次。當這些數據服務完訪問請求後,如果還繼續留存在緩存中的話,就只會白白佔用緩存空間。

由於 LRU 是基於訪問時間的,如果系統對大量數據進行單次查詢,這些數據的 lru 值就很大,使用 LFU 算法就不容易被淘汰。

參考:

《Redis 核心技術與實戰》

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/AnIzuq-t5UB3Y5KfB7ckAA