將 redis 用作快取時, 如果記憶體空間用滿, 就會自動驅逐老的資料。 預設情況下 memcached 就是這種方式, 大部分開發者都比較熟悉。
lru是redis唯一支援的**演算法. 本文詳細介紹用於限制最大記憶體使用量的 maxmemory 指令, 並深入講解 redis 所使用的近似lru演算法。
maxmemory 配置指令
maxmemory 用於指定 redis 能使用的最大記憶體。既可以在 redis.conf 檔案中設定, 也可以在執行過程中通過 config set 命令動態修改。
例如, 要設定 100mb 的記憶體限制, 可以在 redis.conf 檔案中這樣配置:
maxmemory 100mb
1將 maxmemory 設定為 0, 則表示不進行記憶體限制。當然, 對32位系統來說有乙個隱性的限制條件: 最多 3gb 記憶體。
當記憶體使用達到最大限制時, 如果需要儲存新資料, 根據配置的策略(policies)的不同, redis可能直接返回錯誤資訊, 或者刪除部分老的資料。
驅逐策略
達到最大記憶體限制時(maxmemory), redis 根據 maxmemory-policy 配置的策略, 來決定具體的行為。
當前版本,redis 3.0 支援的策略包括:
noeviction: 不刪除策略, 達到最大記憶體限制時, 如果需要更多記憶體, 直接返回錯誤資訊。 大多數寫命令都會導致占用更多的記憶體(有極少數會例外, 如 del )。
allkeys-lru: 所有key通用; 優先刪除最近最少使用(less recently used ,lru) 的 key。
volatile-lru: 只限於設定了 expire 的部分; 優先刪除最近最少使用(less recently used ,lru) 的 key。
allkeys-random: 所有key通用; 隨機刪除一部分 key。
volatile-random: 只限於設定了 expire 的部分; 隨機刪除一部分 key。
volatile-ttl: 只限於設定了 expire 的部分; 優先刪除剩餘時間(time to live,ttl) 短的key。
如果沒有設定 expire 的key, 不滿足先決條件(prerequisites); 那麼 volatile-lru, volatile-random 和 volatile-ttl 策略的行為, 和 noeviction(不刪除) 基本上一致。
您需要根據系統的特徵, 來選擇合適的驅逐策略。 當然, 在執行過程中也可以通過命令動態設定驅逐策略, 並通過 info 命令監控快取的 miss 和 hit, 來進行調優。
一般來說:
如果分為熱資料與冷資料, 推薦使用 allkeys-lru 策略。 也就是, 其中一部分key經常被讀寫. 如果不確定具體的業務特徵, 那麼 allkeys-lru 是乙個很好的選擇。
如果需要迴圈讀寫所有的key, 或者各個key的訪問頻率差不多, 可以使用 allkeys-random 策略, 即讀寫所有元素的概率差不多。
假如要讓 redis 根據 ttl 來篩選需要刪除的key, 請使用 volatile-ttl 策略。
volatile-lru 和 volatile-random 策略主要應用場景是: 既有快取,又有持久key的例項中。 一般來說, 像這類場景, 應該使用兩個單獨的 redis 例項。
值得一提的是, 設定 expire 會消耗額外的記憶體, 所以使用 allkeys-lru 策略, 可以更高效地利用記憶體, 因為這樣就可以不再設定過期時間了。
驅逐的內部實現
驅逐過程可以這樣理解:
客戶端執行乙個命令, 導致 redis 中的資料增加,占用更多記憶體。
redis 檢查記憶體使用量, 如果超出 maxmemory 限制, 根據策略清除部分 key。
繼續執行下一條命令, 以此類推。
在這個過程中, 記憶體使用量會不斷地達到 limit 值, 然後超過, 然後刪除部分 key, 使用量又下降到 limit 值之下。
如果某個命令導致大量記憶體占用(比如通過新key儲存乙個很大的set), 在一段時間內, 可能記憶體的使用量會明顯超過 maxmemory 限制。
近似lru演算法
redis 使用的並不是完全lru演算法。自動驅逐的 key , 並不一定是最滿足lru特徵的那個. 而是通過近似lru演算法, 抽取少量的 key 樣本, 然後刪除其中訪問時間最古老的那個key。
驅逐演算法, 從 redis 3.0 開始得到了巨大的優化, 使用 pool(池子) 來作為候選. 這大大提公升了演算法效率, 也更接近於真實的lru演算法。
在 redis 的 lru 演算法中, 可以通過設定樣本(sample)的數量來調優演算法精度。 通過以下指令配置:
maxmemory-samples 5
1為什麼不使用完全lru實現? 原因是為了節省記憶體。但 redis 的行為和lru基本上是等價的. 下面是 redis lru 與完全lru演算法的乙個行為對比圖。
測試過程中, 依次從第乙個 key 開始訪問, 所以最前面的 key 才是最佳的驅逐物件。
從圖中可以看到三種型別的點, 構成了三個不同的條帶。
淺灰色部分表示被驅逐的物件。
灰色部分表示 「未被驅逐」 的物件。
綠色部分表示後面加入的物件。
在純粹的lru演算法實現中, 前半部分舊的key被釋放了。而 redis 的 lru 演算法只是將時間較長的 key 較大概率地(probabilistically)釋放了。
如你所見, redis 3.0 中, 5樣本的效果比 redis 2.8 要好很多。 當然, redis 2.8 也不錯,最後訪問的key基本上都還留在記憶體中. 在 redis 3.0 中使用 10 樣本時, 已經非常接近純粹的lru演算法了。
注意,lru只是用來**將來可能會繼續訪問某個key的乙個概率模型. 此外,如果資料訪問的情況符合冪律分布(power law), 那麼對於大部分的請求來說, lru都會表現良好。
在模擬中, 我們發現, 如果使用冪律方式訪問, 純粹的lru和redis的結果差別非常, 甚至看不出來。
當然也可以將樣本數量提高到10, 以額外消耗一些cpu為代價, 使得結果更接近於真實的lru, 並通過 cache miss 統計資訊來判斷差異。
Redis六種淘汰策略
將redis用作快取時,如果記憶體空間用滿,就會自動驅逐老的資料。預設情況下 memcached就是這就方式。lru是redis唯一支援的 演算法,本文講解限制最大記憶體使用量的maxmemory指令,並深入講解redis所使用的近似lru演算法。maxmemory用於指定redis能使用的最大記憶...
Redis的六種淘汰策略
將 redis 用作快取時,如果記憶體空間用滿,就會自動驅逐老的資料,淘汰那些老的或者不常用的部分keys,以保證新的資料寫入成功。maxmemory配置指令 maxmemory配置指令用於配置redis儲存資料時指定限制的記憶體大小。通過redis.conf可以設定該指令,或者之後使用config...
配置Redis作為快取(六種淘汰策略)
將 redis 用作快取時,如果記憶體空間用滿,就會自動驅逐老的資料。預設情況下 memcached 就是這種方式,大部分開發者都比較熟悉。lru是redis唯一支援的 演算法.本文詳細介紹用於限制最大記憶體使用量的maxmemory指令,並深入講解 redis 所使用的近似lru演算法。maxme...