《Redis開發與運維》 理解記憶體

2021-10-24 01:40:54 字數 3931 閱讀 5715

二、記憶體管理

三、記憶體優化

重點關注:used_memory_rss、used_memory、mem_fragmentation_ratio(比值)

當mem_fragmentation_ratio>1時,說明碎片率嚴重。

當mem_fragmentation_ratio<1時,說明redis記憶體交換(swap)到硬碟導致,redis效能會很差,甚至僵死。

redis程序內消耗主要包括:自身記憶體(消耗非常少)+物件記憶體+緩衝記憶體+記憶體碎片

子程序記憶體消耗:主要是指執行aof、rdb重寫時redis建立的子程序記憶體消耗。redis執行fork操作產生的子程序記憶體佔用量對外表現為與父程序相同,理論上需要一倍的物理記憶體來完成重寫操作。

子程序記憶體消耗總結如下:

redis主要通過控制記憶體上限和**策略實現記憶體管理。

redis使用maxmemory引數限制最大可用記憶體。redis的記憶體上限也可以通過config set maxmemory程序動態修改。

限制記憶體目的:

注意:maxmemory限制的是redis實際使用的記憶體量,也就是used_memory 統計項對應記憶體。由於記憶體碎片率的存在,實際消耗的記憶體可能會比maxmemory設定的更大,實際使用時要小心這部分記憶體溢位。

redis記憶體**機制主要體現在兩個方面:

redis支援六種記憶體溢位控制策略:

策略說明

noeviction預設策略,不會刪除任何資料,拒絕所有寫入操作返回錯誤資訊 oom,只響應讀操作

volatile-lru根據lru演算法刪除設定了超時屬性的鍵,直到騰出足夠空間為止

allkeys-lru根據lru廢刪除鍵,不管資料有沒有設定超時屬性,直到騰出足夠空間為止

allkeys-random隨機刪除所有鍵,直到騰出足夠空間為止

volatile-random隨機刪除過期鍵,直到騰出足夠空間為止

volatile-ttl根據鍵值物件的ttl屬性,刪除最近將要過期資料

redis4之後支援的記憶體策略:

策略說明

volatile-lfu根據lfu演算法來淘汰過期鍵。

allkeys-lfu根據lfu演算法刪除鍵,不管是否超時,直到騰出足夠空間

lru 演算法:

lru是least recently used的縮寫,即最近最少使用,常用於頁面置換演算法,是為虛擬頁式儲存管理服務的。

實現 lru 演算法除了需要 key/value 字典外,還需要附加乙個鍊錶,鍊錶中的元素按照一定的順序進行排列。當空間滿的時候,會踢掉鍊錶尾部的元素。當字典的某個元素被訪問時,它在鍊錶中的位置會被移動到表頭。所以鍊錶的元素排列順序就是元素最近被訪問的時間順序。位於鍊錶尾部的元素就是不被重用的元素,所以會被踢掉。位於表頭的元素就是最近剛剛被人用過的元素,所以暫時不會被踢。

lfu 演算法:

lfu 是least frequently used的縮寫,表示按最近的訪問頻率進行淘汰,它比 lru 更加精準地表示了乙個key 被訪問的熱度

頻繁執行**記憶體成本很高,建議線上redis記憶體工作在maxmemory>used_memory狀態下,避免頻繁記憶體**開銷

redis儲存的所有值物件在內部定義為redisobject結構體,結構如下:

*ptr欄位:與物件的資料內容相關,如果是整數,直接儲存資料;否則表示指向資料的指標。redis在3。0之後對值物件是字串且長度<=39欄位的資料,內部編碼為embstr型別,字串sds和redisobject一起分配,從而只要一次記憶體操作即可。

高併發寫入場景中,在條件允許情況下,建議字串長度控制在39位元組以內,減少建立redisobject記憶體分配次數,從而提高效能。

共享物件池是指在redis內部維護[0-9999]的整數物件池。建立大量的整數型別redisobject存在記憶體開銷,每個redisobject內部結構至少占用16個位元組,甚至超過了整數自身空間消耗。所以redis記憶體維護乙個[0-9999]整數物件池,用於節約記憶體。除了整數值物件,其他型別如list、hash、set、zset內部元素也可以使用整數物件池。因此開發中在滿足需求的前提下,盡可能使用整數物件以節省記憶體。

需要注意的是物件池並不是只要儲存[0-9999]的整數就可以工作。當設定maxmemory並啟用lru相關淘汰策略:volatile-lru,allkeys-lru時,redis禁止使用共享物件池。

redis沒有使用c語言的字串型別而是自己實現了字串結構,內部簡單動態字串(****** dynamic string,sds)。結構如圖:

使用object encoding命令獲取編碼型別。如下表:

ziplist結構字段含義:乙個ziplist可以包含多個entry(元素),每個entry儲存具體的資料。

(1)zlbytes: 記錄整個壓縮列表所佔位元組長度,方便重新調整ziplist空間。

(2) zltail:記錄距離尾節點的偏移量,方便尾節點彈出操作。

(3)zllen: 記錄壓縮鍊錶節點數量

(4)entry: 記錄具體的節點,長度根據實際儲存的資料而定。

(5) zlend: 記錄列表結尾,占用乙個位元組。

ziplist結構特點如下:

(1)內部表現為資料緊湊排列的一塊連續記憶體陣列

(2)可以模擬雙向鍊錶結構,以o(1)時間複雜度入隊和出隊

(3)新增刪除操作涉及記憶體重新分配或釋放,加大了操作的複雜性

(4)讀寫操作涉及複雜的指標移動,最壞時間複雜度是o(n2)

(5)適合儲存小物件和長度有限的資料

過多的鍵同樣會消耗大量記憶體,通過在客戶端預估鍵規模,把大量鍵分組對映到多個hash結構中減低鍵的數量。

hash結構降低鍵數量分析:

根據鍵規模在客戶端通過分組對映到一組hash物件中,如存在100萬個鍵,可以對映到1000個hash中,每個hash儲存1000個元素。

hash的field可用於記錄原始key字串,方便雜湊查詢。

hash的value儲存原始值物件,確保不要超過hash-max-ziplist-value限制。

通過上面的測試資料,可以說明:

注意:1.hash型別節省記憶體的原理是使用ziplist編碼,如果使用hashtable編碼方式反而會增加記憶體消耗。

2. hash重構後所有的鍵無法再使用超時(expire)和lru淘汰機制自動刪除,需要手動維護刪除

3. 對於大物件,如1kb以上的物件,使用hash-ziplist結構控制鍵數量反而得不償失

4. 對於大量小物件的儲存場景,非常適合使用ziplist編碼的hash型別控制鍵的規模來降低記憶體

redis 開發與運維 1

由於手上負責的專案很依賴redis,而且redis曾經出過問題,故決定好好系統學習一下redis的知識,本文打算先介紹一下redis的基礎知識 首先我們必須明確的幾個知識點1 1 keys 這個命令可以檢視所有的鍵,這是這個 當前db所有的key 127.0 0.1 6379 keys 1 haha...

《Redis開發與運維》筆記 初識Redis

目錄 redis優點 redis特性 速度快基於鍵值對的資料結構伺服器 豐富的功能 簡單穩定 客戶端語言多 持久化主從複製 高可用和分布式 redis使用場景 redis可以做什麼 redis不可以做什麼 用好redis的建議 切勿當作黑盒使用,開發與運維同樣重要 閱讀原始碼 redis重大版本 r...

《Redis開發與運維》 列表List

list 有序,可重複 redis中列表 list 型別是用來儲存多個有序的字串,列表中的每個字串成為元素 element 乙個列表最多可以儲存2 32 1個元素。命令 新增操作 rpush key value value 從右向左插入元素 lpush key value value 從左向右插入元...