redis作為快取的過期策略差別

2021-10-08 20:58:26 字數 3143 閱讀 2796

將 redis 用作快取時, 如果記憶體空間用滿, 就會自動驅逐老的資料。 預設情況下 memcached 就是這種方式, 大部分開發者都比較熟悉。

lru是redis唯一支援的**演算法. 本文詳細介紹用於限制最大記憶體使用量的 maxmemory 指令, 並深入講解 redis 所使用的近似lru演算法。

maxmemory 配置指令

maxmemory 用於指定 redis 能使用的最大記憶體。既可以在 redis.conf 檔案中設定, 也可以在執行過程中通過 config set 命令動態修改。

例如, 要設定 100mb 的記憶體限制, 可以在 redis.conf 檔案中這樣配置:

maxmemory 100mb

將 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

為什麼不使用完全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 即可。

redis作為快取的過期策略差別

將 redis 用作快取時,如果記憶體空間用滿,就會自動驅逐老的資料。預設情況下 memcached 就是這種方式,大部分開發者都比較熟悉。lru是redis唯一支援的 演算法.本文詳細介紹用於限制最大記憶體使用量的 maxmemory 指令,並深入講解 redis 所使用的近似lru演算法。max...

Redis快取鍵的過期策略

命令名功能 expire 將鍵的生存時間設定為ttl秒 pexpire 將鍵的生存時間設定為ttl毫秒 expireat 將鍵的生存時間設定為timestamp指定的秒數時間戳 pexpireat 將鍵的生存時間設定為timestamp指定的毫秒數時間戳 前三個命令最終都會轉換成pexpireat命...

redis 快取的過期刪除策略

世界上並沒有完美的程式,但是我們並不因此而沮喪,因為寫程式就是乙個不斷追求完美的過程。快取過期以後如何刪除呢?第一,主動刪除,即後台建立定時任務,每隔一段時間遍歷所有有過期時間的快取,判斷是否過期,如果過期則進行刪除 第二,被動刪除,即每次取資料前判斷一下所取的資料是否有過期時間設定,如果有,判斷其...