redis-淘汰策略


將redis用作緩存時,如果內存空間用滿,就會自動驅逐老的數據。默認情況下,memcached就是這種方式。


LRU是Redis唯一支持的回收算法。

maxmemory配置指令

maxmemory用於指定Redis能使用的最大內存。既可以在redis.conf文件中配置,也可以在運行過程中通過CONFIG SET命令動態修改。

例如,要設置100MB的內存限制,可以在redis.conf文件中這樣配置

maxmemory 100mb

# 將maxmemory設置為0,則表示不進行內存限制。當然,對32位系統來說有一個隱性的限制條件:最多3GB內存。
當內存使用達到最大限制時,如果需要存儲新數據,根據配置的淘汰策略不同,Redis可能直接返回錯誤信息,或者刪除部分老的數據。

 

淘汰策略

達到最大內存限制(maxmemory),redis根據maxmemory-policy配置的策略,來決定具體的行為。

  • noeviction:不刪除策略。達到最大內存限制時,如果需要更多內存,直接返回錯誤信息。大多數寫命令都會導致占用更多的內存(極少數里外:DEL)
  • allkeys-lru:所有key通用;優先刪除最近最少使用的key
  • volatile-lru:只限於設置了expire的部分;優先刪除最近最少使用的key
  • allkeys-random:所有key通用;隨機刪除一部分key
  • volatile-random:只限於設置了expire的部分;隨機刪除一部分key
  • volatile-ttl:只限於設置了expire的部分;優先刪除剩余時間短的key

如果沒有設置expire的key,不滿足先決條件;那么volatile-lru,volatile-random和volatile-ttl策略的行為,和noeviction(不刪除)基本上一致。

需要根據系統的特征,來選擇合適的驅逐策略。當然,在運行過程中也可以通過命令動態設置淘汰策略,並通過INFO命令監控緩存的miss和hit,來進行調優

一般來說:

  • 如果分為熱數據與冷數據,推薦使用allkeys-lru策略。也就是說,其中一部分key經常被讀寫。如果不確定具體的業務特征,那么allkeys-lru是一個很好的選擇。
  • 如果需要循環讀寫所有的keys,或者各個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

為什么不使用完全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 統計信息來判斷差異。

設置樣本大小很容易, 使用命令 CONFIG SET maxmemory-samples <count> 即可。

原文:https://blog.csdn.net/ligupeng7929/article/details/79603060


免責聲明!

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



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