天天看點

Java架構進階之Redis記憶體回收政策

1、背景

作為時下熱門的存儲系統,Redis在系統扮演重要角色。不管是 session 存儲還是熱點資料的緩存,還是其他場景,都會用到 Redis。在生産環境我們偶爾會遇到 Redis 伺服器記憶體不夠的情況,那對于這種情況 Redis 的記憶體是如何回收處理的呢?

2、Redis 記憶體設定

我們都知道如果我們要設定 Redis 的最大記憶體大小隻需要在配置檔案redis.conf 中配置一行 maxmemory xxx 即可,或者我們通過 config set 指令在運作時動态配置 Redis 的記憶體大小。

Java架構進階之Redis記憶體回收政策

3、Redis 記憶體過期政策

3.1、過期政策的配置

當 Redis 記憶體不夠的時候,需要知道 Redis 是根據什麼政策來淘汰資料的,在配置檔案中使用 maxmemory-policy 來配置政策,如下圖:

Java架構進階之Redis記憶體回收政策

我們可以看到政策的值由如下幾種:

1.volatile-lru: 在所有帶有過期時間的 key 中使用 LRU 算法淘汰資料;

2.alkeys-lru: 在所有的 key 中使用最近最少被使用 LRU 算法淘汰資料,保證新加入的資料正常;

3.volatile-random: 在所有帶有過期時間的 key 中随機淘汰資料;

4.allkeys-random: 在所有的 key 中随機淘汰資料;

5.volatile-ttl: 在所有帶有過期時間的 key 中,淘汰最早會過期的資料;

6.noeviction: 不回收,當達到最大記憶體的時候,在增加新資料的時候會傳回 error,不會清除舊資料,這是 Redis 的預設政策;

volatile-lru, volatile-random, volatile-ttl 這幾種情況在 Redis 中沒有帶有過期 Key 的時候跟 noeviction 政策是一樣的。淘汰政策是可以動态調整的,調整的時候是不需要重新開機的,原文是這樣說的,我們可以根據自己 Redis 的模式來動态調整政策。”To pick the right eviction policy is important depending on the access pattern of your application, however you can reconfigure the policy at runtime while the application is running, and monitor the number of cache misses and hits using the Redis INFO output in order to tune your setup.“

3.2、政策的執行過程

1)用戶端運作指令,添加資料申請記憶體;

2)Redis 會檢查記憶體的使用情況,如果已經超過的最大限制,就是根據配置的記憶體淘汰政策去淘汰相應的 key,進而保證新資料正常添加;

3.)繼續執行指令。

3.3、近似的 LRU 算法

Redis 中的 LRU 算法不是精确的 LRU 算法,而是一種經過采樣的LRU,我們可以通過在配置檔案中設定 maxmemory-samples 5 來設定采樣的大小,預設值為 5,我們可以自行調整。官方提供的采用對比如下,我們可以看到當采用數設定為 10 的時候已經很接近真實的 LRU 算法了。

Java架構進階之Redis記憶體回收政策

在 Redis 3.x 以上的版本的中做過優化,目前的近似 LRU 算法以及提升了很大的效率,Redis 之是以不采樣實際的 LRU 算法,是因為會耗費很多的記憶體,原文是這樣說的The reason why Redis does not use a true LRU implementation is because it costs more memory.

4、Key 的過期政策

4.1、設定帶有過期時間的 key

前面介紹了 Redis 的記憶體回收政策,下面我們看看 Key 的過期政策,提到 Key 的過期政策,我們說的當然是帶有 expire 時間的 key,如下:

Java架構進階之Redis記憶體回收政策

通過 redis> set name ziyouu ex 100 指令我們在 Redis 中設定一個 key 為 name,值為 ziyouu 的資料,從上面的截圖中我們可以看到右下角有個 TTL,并且每次重新整理都是在減少的,說明我們設定帶有過期時間的 key 成功了。

4.2、Redis 如何清除帶有過期時間的 key

對于如何清除過期的 key 通常我們很自然的可以想到就是我們可以給每個 key 加一個定時器,這樣當時間到達過期時間的時候就自動删除 key,這種政策我們叫定時政策。這種方式對記憶體是友好的,因為可以及時清理過期的可以,但是由于每個帶有過期時間的 key 都需要一個定時器,是以這種方式對 CPU 是不友好的,會占用很多的 CPU,另外這種方式是一種主動的行為。

有主動也有被動,我們可以不用定時器,而是在每次通路一個 key 的時候再去判斷這個 key 是否到達過期時間了,過期了就删除掉。這種方式我們叫做惰性政策,這種方式對 CPU 是友好的,但是對應的也有一個問題,就是如果這些過期的 key 我們再也不會通路,那麼永遠就不會删除了。

Redis 伺服器在真正實作的時候上面的兩種方式都會用到,這樣就可以得到一種折中的方式。

另外在定時政策中,從官網我們可以看到如下說明

Specifically this is what Redis does 10 times per second:

1.Test 20 random keys from the set of keys with an associated expire.

2.Delete all the keys found expired.

3.If more than 25% of keys were expired, start again from step

意思是說 Redis 會在有過期時間的 Key 集合中随機 20 個出來,删掉已經過期的 Key,如果比例超過 25%,再重新執行操作。每秒中會執行 10 個這樣的操作。

文章較長,感謝您的閱讀。對文章如有疑問,歡迎提出。望分享的内容對大家有所幫助。搜集整理了一些Java資料,包括Java進階學習路線以及對應學習資料,還有一些大廠面試題,需要的朋友可以自行領取:Java進階架構學習資料分享+架構師成長之路