Redis學習筆記2-使用 Redis 作為 LRU 緩存


當 Redis 作為緩存使用時,當你添加新的數據時,有時候很方便使 Redis 自動回收老的數據。LRU 實際上是被唯一支持的數據移除方法。Redis 的 maxmemory 指令,用於限制內存使用到一個固定的容量,也包含深入探討 Redis 使用的 LRU 算法,一個近似准確的 LRU。

maxmemory 配置指令(configuration directive)

maxmemory 配置指令是用來配置 Redis 為數據集使用指定的內存容量大小。可以使用 redis.conf 文件來設置配置指令,或者之后在運行時使用 CONFIG SET 命令。

例如,為了配置內存限制為 100MB,可以在 redis.conf 文件中使用以下指令

maxmemory 100mb

設置 maxmemory 為 0,表示沒有內存限制。這是 64 位系統的默認行為,32 位的系統則使用 3G 大小作為隱式的內存限制。

當指定的內存容量到達時,需要選擇不同的行為,即策略。Redis 可以只為命令返回錯誤,這樣將占用更多的內存,或者每次添加新數據時,回收掉一些舊的數據以避免內存限制。

回收策略(Eviction policies)

當 maxmemory 限制到達的時候,Redis 將采取的准確行為是由 maxmemory-policy 配置指令配置的。

以下策略可用:

  • noeviction:當到達內存限制時返回錯誤。當客戶端嘗試執行命令時會導致更多內存占用(大多數寫命令,除了 DEL 和一些例外)。
  • allkeys-lru:回收最近最少使用(LRU)的鍵,為新數據騰出空間。
  • volatile-lru:回收最近最少使用(LRU)的鍵,但是只回收有設置過期的鍵,為新數據騰出空間。
  • allkeys-random:回收隨機的鍵,為新數據騰出空間。
  • volatile-random:回收隨機的鍵,但是只回收有設置過期的鍵,為新數據騰出空間。
  • volatile-ttl:回收有設置過期的鍵,嘗試先回收離 TTL 最短時間的鍵,為新數據騰出空間。

當沒有滿足前提條件的話,volatile-lru,volatile-random 和 volatile-ttl 策略就表現得和 noeviction 一樣了。

選擇正確的回收策略是很重要的,取決於你的應用程序的訪問模式,但是,你可以在程序運行時重新配置策略,使用 INFO 輸出來監控緩存命中和錯過的次數,以調優你的設置。

一般經驗規則:

  • M 如果你期待你的用戶請求呈現冪律分布(power-law distribution),也就是,你期待一部分子集元素被訪問得遠比其他元素多,可以使用 allkeys-lru 策略。在你不確定時這是一個好的選擇。
  • 如果你是循環周期的訪問,所有的鍵被連續掃描,或者你期待請求正常分布(每個元素以相同的概率被訪問),可以使用 allkeys-random 策略。
  • 如果你想能給 Redis 提供建議,通過使用你創建緩存對象的時候設置的 TTL 值,確定哪些對象應該被過期,你可以使用 volatile-ttl 策略。

當你想使用單個實例來實現緩存和持久化一些鍵,allkeys-lru 和 volatile-random 策略會很有用。但是,通常最好是運行兩個 Redis 實例來解決這個問題。

另外值得注意的是,為鍵設置過期時間需要消耗內存,所以使用像 allkeys-lru 這樣的策略會更高效,因為在內存壓力下沒有必要為鍵的回收設置過期時間。

回收過程 (Eviction process)

理解回收的過程是這么運作的非常的重要:

  • 一個客戶端運行一個新命令,添加了新數據。
  • Redis 檢查內存使用情況,如果大於 maxmemory 限制,根據策略來回收鍵。
  • 一個新的命令被執行,如此等等。

通過檢查,然后回收鍵以返回到限制以下,來連續不斷的穿越內存限制的邊界。

如果一個命令導致大量的內存被占用 (像一個很大的集合交集保存到一個新的鍵),一會功夫內存限制就會被這個明顯的內存量所超越。

近似的 LRU 算法(Approximated LRU algorithm)

Redis 的 LRU 算法不是一個精確的實現。這意味着 Redis 不能選擇最佳候選鍵來回收,也就是最久錢被訪問的那些鍵。相反,會嘗試運營一個近似的 LRU 算法,通過采樣一小部分鍵,然后在采樣鍵中回收最適合(擁有最久訪問時間)的那個。

Redis 的 LRU 算法有一點很重要,你可以調整算法的精度,通過改變每次回收時檢查的采樣數量。這個參數可以通過如下配置指令

maxmemory-samples 5 

Redis 沒有使用真實的 LRU 實現的原因,是因為這會消耗更多的內存。然而,近似值對使用 Redis 的應用來說基本上也是等價的。為 Redis 使用的 LRU 近似值和真實 LRU 之間的比較。

Redis 服務被填充了指定數量的鍵。鍵被從頭訪問到尾,所以第一個鍵是 LRU 算法的最佳候選回收鍵。然后,再新添加 50% 的鍵,強制一般的舊鍵被回收。

在理論的 LRU 實現中,我們期待看到的是,在舊鍵中第一半會過期。而 Redis 的 LRU 算法則只是概率性的過期這些舊鍵。

你可以看到,同樣采用 5 個采樣,Redis 3.0 表現得比 Redis 2.8 要好,Redis 2.8 中最近被訪問的對象之間的對象仍然被保留。在 Redis 3.0 中使用 10 為采樣大小,近似值已經非常接近理論性能。

注意,LRU 只是一個預言指定鍵在未來如何被訪問的模式。另外,如果你的數據訪問模式非常接近冪律,大多數的訪問都將集中在一個集合中,LRU 近似算法將能處理得很好。

在模擬實驗的過程中,我們發現使用冪律訪問模式,真實的 LRU 算法和 Redis 的近似算法之間的差異非常小,或者根本就沒有。

然而,你可以提高采樣大小到 10,這會消耗額外的 CPU,來更加近似於真實的 LRU 算法,看看這會不會使你的緩存錯失率有差異。

使用 CONFIG SET maxmemory-samples 命令在生產環境上試驗各種不同的采樣大小值是很簡單的。

  

  


免責聲明!

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



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