Redis 緩存過期(maxmemory) 配置/算法 詳解


LRU(Least Recently Used) 最近最少使用算法是眾多置換算法中的一種。 

Redis中有一個 maxmemory 概念,主要是為了將使用的內存限定在一個固定的大小。Redis 用到的 LRU 算法,是一種近似的LRU算法。

1、設置 maxmemory

上面已經說過 maxmemory 是為了限定 Redis 最大內存使用量。有多種方法設定它的大小。其中一種方法是通過 CONFIG SET 設定,如下:

127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "0"
127.0.0.1:6379> CONFIG SET maxmemory 100MB
OK
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "104857600"

另一種方法是修改配置文件 redis.conf

maxmemory 100mb

注意,在 64bit 系統下,maxmemory 設置為 0 表示不限制 Redis 內存使用,在 32bit 系統下,maxmemory 隱式不能超過 3GB。 

當 Redis 內存使用達到指定的限制時,就需要選擇一個置換的策略。

2、置換策略

當 Redis 內存使用達到 maxmemory 時,需要選擇設置好的 maxmemory-policy 進行對老數據的置換。

下面是可以選擇的置換策略:

  • noeviction: 不進行置換,表示即使內存達到上限也不進行置換,所有能引起內存增加的命令都會返回error
  • allkeys-lru: 優先刪除掉最近最不經常使用的key,用以保存新數據
  • volatile-lru: 只從設置失效(expire set)的key中選擇最近最不經常使用的key進行刪除,用以保存新數據
  • allkeys-random: 隨機從all-keys中選擇一些key進行刪除,用以保存新數據
  • volatile-random: 只從設置失效(expire set)的key中,選擇一些key進行刪除,用以保存新數據
  • volatile-ttl: 只從設置失效(expire set)的key中,選出存活時間(TTL)最短的key進行刪除,用以保存新數據

設置 maxmemory-policy 的方法 和 設置 maxmemory 方法類似,通過 redis.conf 或是通過 CONFIG SET 動態修改。

如果沒有匹配到可以刪除的 key,那么 volatile-lruvolatile-random 和 volatile-ttl 策略和 noeviction 替換策略一樣——不對任何 key 進行置換。

選擇合適的置換策略是很重要的,這主要取決於你的應用的訪問模式,當然你也可以動態的修改置換策略,並通過用 Redis 命令——INFO 去輸出 cache 的命中率情況,進而可以對置換策略進行調優。

一般來說,有這樣一些常用的經驗:

  • 在所有的 key 都是最近最經常使用,那么就需要選擇 allkeys-lru 進行置換最近最不經常使用的 key,如果你不確定使用哪種策略,那么推薦使用 allkeys-lru
  • 如果所有的 key 的訪問概率都是差不多的,那么可以選用 allkeys-random 策略去置換數據
  • 如果對數據有足夠的了解,能夠為 key 指定 hint(通過expire/ttl指定),那么可以選擇 volatile-ttl 進行置換

volatile-lru 和 volatile-random 經常在一個Redis實例既做cache又做持久化的情況下用到,然而,更好的選擇使用兩個Redis實例來解決這個問題。

設置是失效時間 expire 會占用一些內存,而采用 allkeys-lru 就沒有必要設置失效時間,進而更有效的利用內存。

3、置換策略是如何工作的

理解置換策略的執行方式是非常重要的,比如:

  • 客戶端執行一條新命令,導致數據庫需要增加數據(比如set key value)
  • Redis會檢查內存使用,如果內存使用超過 maxmemory,就會按照置換策略刪除一些 key
  • 新的命令執行成功

我們持續的寫數據會導致內存達到或超出上限 maxmemory,但是置換策略會將內存使用降低到上限以下。

如果一次需要使用很多的內存(比如一次寫入一個很大的set),那么,Redis 的內存使用可能超出最大內存限制一段時間。

4、近似 LRU 算法

Redis 中的 LRU 不是嚴格意義上的LRU算法實現,是一種近似的 LRU 實現,主要是為了節約內存占用以及提升性能。Redis 有這樣一個配置 —— maxmemory-samples,Redis 的 LRU 是取出配置的數目的key,然后從中選擇一個最近最不經常使用的 key 進行置換,默認的 5,如下:

maxmemory-samples 5

可以通過調整樣本數量來取得 LRU 置換算法的速度或是精確性方面的優勢。

Redis 不采用真正的 LRU 實現的原因是為了節約內存使用。雖然不是真正的 LRU 實現,但是它們在應用上幾乎是等價的。下圖是 Redis 的近似 LRU 實現和理論 LRU 實現的對比:

測試開始首先在 Redis 中導入一定數目的 key,然后從第一個 key 依次訪問到最后一個key,因此根據 LRU 算法第一個被訪問的 key 應該最新被置換,之后再增加 50% 數目的 key,導致 50% 的老的 key 被替換出去。 

在上圖中你可以看到三種類型的點,組成三種不同的區域:

  • 淡灰色的是被置換出去的key
  • 灰色的是沒有被置換出去的key
  • 綠色的是新增加的key

理論 LRU 實現就像我們期待的那樣,最舊的 50% 數目的 key 被置換出去,Redis 的 LRU 將一定比例的舊 key 置換出去。

可以看到在樣本數為 5 的情況下,Redis3.0 要比 Redis2.8 做的好很多,Redis2.8 中有很多應該被置換出去的數據沒有置換出去。在樣本數為10的情況下,Redis3.0 很接近真正的 LRU 實現。

LRU 是一個預測未來我們會訪問哪些數據的模型,如果我們訪問數據的形式接近我們預想——冪律,那么近似 LRU 算法實現將能處理的很好。

在模擬測試中我們可以發現,在冪律訪問模式下,理論 LRU 和 Redis 近似 LRU 的差距很小或者就不存在差距。

如果你將 maxmemory-samples 設置為 10,那么 Redis 將會增加額外的 CPU 開銷以保證接近真正的 LRU 性能,可以通過檢查命中率來查看有什么不同。

通過 CONFIG SET maxmemory-samples <count> 動態調整樣本數大小,做一些測試驗證你的猜想。

 

 

參考:

http://redis.io/topics/lru-cache

Redis中的maxmemory怎么設置?

Redis內存使用達到maxmemory設定值后玩家數據無法寫入解決

Redis系列之三生產環境實戰須知


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM