推薦學習:
redis記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰策略。
記憶體。
如果達到設定的上限,Redis的寫命令會返回錯誤資訊(但是讀命令還可以正常返回。)或者你可以設定記憶體淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的內容。
Redis 快取有哪些淘汰策略?
會進行淘汰的 7 種策略,我們可以再進一步根據淘汰候選資料集的範圍把它們分成兩類:
策略 | 規則 |
---|---|
volatile-ttl | 在篩選時,會針對設定了過期時間的鍵值對,根據過期時間的先後進行刪除,越早過期的越先被刪除。 |
volatile-random | 在設定了過期時間的鍵值對中,進行隨機刪除。 |
volatile-lru | 使用 LRU 演演算法篩選設定了過期時間的鍵值對 |
volatile-lfu | 使用 LFU 演演算法選擇設定了過期時間的鍵值對 |
策略 | 規則 |
---|---|
allkeys-random | 從所有鍵值對中隨機選擇並刪除資料; |
allkeys-lru | 使用 LRU 演演算法在所有資料中進行篩選 |
vallkeys-lfu | 使用 LFU 演演算法在所有資料中進行篩選 |
是按照最近最少使用的原則來篩選資料,最不常用的資料會被篩選出來,而最近頻繁使用的資料會留在快取中。
那具體是怎麼篩選的呢?LRU 會把所有的資料組織成一個連結串列,連結串列的頭和尾分別表示 MRU 端和 LRU 端,分別代表最近最常使用的資料和最近最不常用的資料。
LRU 演演算法背後的想法非常樸素:它認為剛剛被存取的資料,肯定還會被再次存取,所以就把它放在 MRU 端;長久不存取的資料,肯定就不會再被存取了,所以就讓它逐漸後移到 LRU 端,在快取滿時,就優先刪除它。
問題:LRU 演演算法在實際實現時,需要用連結串列管理所有的快取資料,這會帶來額外的空間開銷。而且,當有資料被存取時,需要在連結串列上把該資料移動到 MRU 端,如果有大量資料被存取,就會帶來很多連結串列移動操作,會很耗時,進而會降低 Redis 快取效能。
解決:
在 Redis 中,LRU 演演算法被做了簡化,以減輕資料淘汰對快取效能的影響。具體來說,Redis 預設會記錄每個資料的最近一次存取的時間戳(由鍵值對資料結構 RedisObject 中的 lru 欄位記錄)。然後,Redis 在決定淘汰的資料時,第一次會隨機選出 N 個資料,把它們作為一個候選集合。接下來,Redis 會比較這 N 個資料的 lru 欄位,把 lru 欄位值最小的資料從快取中淘汰出去。
當需要再次淘汰資料時,Redis 需要挑選資料進入第一次淘汰時建立的候選集合。這兒的挑選標準是:能進入候選集合的資料的 lru 欄位值必須小於候選集合中最小的 lru 值。當有新資料進入候選資料集後,如果候選資料集中的資料個數達到了 maxmemory-samples,Redis 就把候選資料集中 lru 欄位值最小的資料淘汰出去。
使用建議:
一旦被淘汰的資料選定後,如果這個資料是乾淨資料,那麼我們就直接刪除;如果這個資料是髒資料,我們需要把它寫回資料庫。
那怎麼判斷一個資料到底是乾淨的還是髒的呢?
即使淘汰的資料是髒資料,Redis 也不會把它們寫回資料庫。所以,我們在使用 Redis 快取時,如果資料被修改了,需要在資料修改時就將它寫回資料庫。否則,這個髒資料被淘汰時,會被 Redis 刪除,而資料庫裡也沒有最新的資料了。
1、控制key的數量:當使用Redis儲存大量資料時,通常會存在大量鍵,過多的鍵同樣會消耗大量記憶體。Redis本質是一個資料結構伺服器,它為我們提供多種資料結構,如hash,list,set,zset 等結構。使用Redis時不要進入一個誤區,大量使用get/set這樣的API,把Redis當成Memcached使用。對於儲存相同的資料內容利用Redis的資料結構降低外層鍵的數量,也可以節省大量記憶體。
2、縮減鍵值物件,降低Redis記憶體使用最直接的方式就是縮減鍵(key)和值(value)的長度。
3、編碼優化。Redis對外提供了string,list,hash,set,zet等型別,但是Redis內部針對不同型別存在編碼的概念,所謂編碼就是具體使用哪種底層資料結構來實現。編碼不同將直接影響資料的記憶體佔用和讀寫效率。
type欄位:
利用集合型別資料,因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。儘可能使用雜湊表(hashes),雜湊表(是說雜湊表裡面儲存的數少)使用的記憶體非常小,所以你應該儘可能的將你的資料模型抽象到一個雜湊表裡面。比如你的web系統中有一個使用者物件,不要為這個使用者的名稱,姓氏,郵箱,密碼設定單獨的key,而是應該把這個使用者的所有資訊儲存到一張雜湊表裡面。
encoding欄位:
採用不同的編碼實現記憶體佔用存在明顯差異
lru欄位:
開發提示:可以使用scan + object idletime 命令批次查詢哪些鍵長時間未被存取,找出長時間不存取的鍵進行清理降低記憶體佔用。
refcount欄位:
當物件為整數且範圍在[0-9999]時,Redis可以使用共用物件的方式來節省記憶體。
ptr欄位 :
開發提示:高並行寫入場景中,在條件允許的情況下建議字串長度控制在39位元組以內,減少建立redisObject記憶體分配次數從而提高效能。
為什麼開啟maxmemory和LRU淘汰策略後物件池無效?
LRU演演算法需要獲取物件最後被存取時間,以便淘汰最長未存取資料,每個物件最後存取時間儲存在redisObject物件的lru欄位。物件共用意味著多個參照共用同一個redisObject,這時lru欄位也會被共用,導致無法獲取每個物件的最後存取時間。如果沒有設定maxmemory,直到記憶體被用盡Redis也不會觸發記憶體回收,所以共用物件池可以正常工作。
綜上所述,共用物件池與maxmemory+LRU策略衝突,使用時需要注意。
為什麼只有整數物件池?
首先整數物件池複用的機率最大,其次物件共用的一個關鍵操作就是判斷相等性,Redis之所以只有整數物件池,是因為整數比較演演算法時間複雜度為O(1),只保留一萬個整數為了防止物件池浪費。如果是字串判斷相等性,時間複雜度變為O(n),特別是長字串更消耗效能(浮點數在Redis內部使用字串儲存)。對於更復雜的資料結構如hash,list等,相等性判斷需要O(n2)。對於單執行緒的Redis來說,這樣的開銷顯然不合理,因此Redis只保留整數共用物件池。
字串結構:
預分配機制:
字串重構:基於hash型別的二級編碼方式。
當Redis記憶體不足時,首先考慮的問題不是加機器做水平擴充套件,應該先嚐試做記憶體優化。當遇到瓶頸時,再去考慮水平擴充套件。即使對於叢集化方案,垂直層面優化也同樣重要,避免不必要的資源浪費和叢集化後的管理成本。
推薦學習:
以上就是詳細解析Redis記憶體滿了怎麼去優化的詳細內容,更多請關注TW511.COM其它相關文章!