這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了redis的記憶體滿了應該怎麼優化的相關問題,還包括了淘汰機制、LRU演算法以及處理淘汰的數據,希望對大家有幫助。
推薦學習:Redis學習教學
redis內存數據集大小上升到一定大小的時候,就會施行資料淘汰策略。
記憶體。
如果達到設定的上限,Redis的寫指令會回傳錯誤訊息(但是讀取指令還可以正常回傳。)或者你可以設定記憶體淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的內容。
Redis 快取有哪些淘汰策略?
會進行淘汰的7 種策略,我們可以再進一步根據淘汰候選資料集的範圍把它們分成兩類:
策略 | 規則 |
---|---|
volatile-ttl | 在篩選時,會針對設定了過期時間的鍵值對,根據過期時間的先後進行刪除,越早過期的越先被刪除。 |
volatile-random | 在設定了過期時間的鍵值對中,進行隨機刪除。 |
volatile-lru | 使用LRU 演算法篩選設定了過期時間的鍵值對 |
使用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教學
#以上是詳細解析Redis記憶體滿了怎麼去優化的詳細內容。更多資訊請關注PHP中文網其他相關文章!