Redis記憶體模型 2 儲存細節

2022-07-17 16:36:18 字數 3552 閱讀 2285

先看一下執行set hellow world時,所涉及的資料模型:

(1)dictentry:redis是key-value資料庫,因此對每個鍵值對都會有乙個dictentry,裡面儲存了指向key和value的指標;next指向下乙個dictentry,與本key-value無關。

(2)key:圖中右上角可見,key(」hello」)並不是直接以字串儲存,而是儲存在sds結構中。

(3)val:value(「world」)既不是直接以字串儲存,也不是像key一樣直接儲存在sds中,而是儲存在redisobject中。實際上,不論value是5種型別的哪一種,都是通過redisobject來儲存的;而redisobject中的type欄位指明了value物件的型別,ptr欄位則指向物件所在的位址。不過可以看出,字串物件雖然經過了redisobject的包裝,但仍然需要通過sds儲存。

(4)ptr:ptr指標指向具體的資料,如上圖,ptr指向包含字串world的sds。

(5)jemalloc:無論是dictentry物件,還是redisobject、sds物件,都需要記憶體分配器(如jemalloc)分配記憶體進行儲存。以dictentry物件為例,有3個指標組成,在64位機器下佔24個位元組,jemalloc會為它分配32位元組大小的記憶體單元。

redis在編譯時便會指定記憶體分配器;記憶體分配器可以是 libc 、jemalloc或者tcmalloc,預設是jemalloc。

jemalloc作為redis的預設記憶體分配器,在減小記憶體碎片方面做的相對比較好。jemalloc在64位系統中,將記憶體空間劃分為小、大、巨大三個範圍;每個範圍內又劃分了許多小的記憶體塊單位;當redis儲存資料時,會選擇大小最合適的記憶體塊進行儲存。

redis物件有5種型別;無論是哪種型別,redis都不會直接儲存,而是通過redisobject物件進行儲存。

redisobject物件非常重要,redis物件的型別、內部編碼、記憶體**、共享物件等功能,都需要redisobject支援,下面將通過redisobject的結構來說明它是如何起作用的。

定義如下(不同版本的redis可能稍稍有所不同):

typedef struct redisobject  robj;
redisobject的每個欄位的含義和作用如下:

type

type欄位表示物件的型別,佔4個位元;目前包括redis_string(字串)、redis_list (列表)、redis_hash(雜湊)、redis_set(集合)、redis_zset(有序集合)。

當我們執行type命令時,便是通過讀取redisobject的type欄位獲得物件的型別:

encoding表示物件的內部編碼,佔4個位元。對於redis支援的每種型別,都有至少兩種內部編碼,例如對於字串,有int、embstr、raw三種編碼。通過encoding屬性,redis可以根據不同的使用場景來為物件設定不同的編碼,大大提高了redis的靈活性和效率。

通過object encoding命令,可以檢視物件採用的編碼方式:

ru記錄的是物件最後一次被命令程式訪問的時間,佔據的位元數不同的版本有所不同(如4.0版本佔24位元,2.6版本佔22位元)。

通過對比lru時間與當前時間,可以計算某個物件的空轉時間;object idletime命令可以顯示該空轉時間(單位是秒)。object idletime命令的乙個特殊之處在於它不會改變物件的lru值。

lru值除了通過object idletime命令列印之外,還與redis的記憶體**有關係:如果redis開啟了maxmemory選項,且記憶體**演算法選擇的是volatile-lru或allkeys—lru,那麼當redis記憶體占用超過maxmemory指定的值時,redis會優先選擇空轉時間最長的物件進行釋放。

refcountrefcount記錄的是該物件被引用的次數,型別為整型。refcount的作用,主要在於物件的引用計數和記憶體**。當建立新物件時,refcount初始化為1;當有新程式使用該物件時,refcount加1;當物件不再被乙個新程式使用時,refcount減1;當refcount變為0時,物件占用的記憶體會被釋放。

共享物件redis中被多次使用的物件(refcount>1),稱為共享物件。redis為了節省記憶體,當有一些物件重複出現時,新的程式不會建立新的物件,而是仍然使用原來的物件。

目前共享物件僅支援整數值的字串物件。之所以如此,實際上是對記憶體和cpu(時間)的平衡:共享物件雖然會降低記憶體消耗,但是判斷兩個物件是否相等卻需要消耗額外的時間。對於整數值,判斷操作複雜度為o(1);對於普通字串,判斷複雜度為o(n);而對於雜湊、列表、集合和有序集合,判斷的複雜度為o(n^2)。雖然共享物件只能是整數值的字串物件,但是5種型別都可能使用共享物件。

redis伺服器在初始化時,會建立10000個字串物件,值分別是09999的整數值;當redis需要使用值為09999的字串物件時,可以直接使用這些共享物件。10000這個數字可以通過調整引數redis_shared_integers(4.0中是obj_shared_integers)的值進行改變。

!(
ptr見上文。

總結

綜上所述,redisobject的結構與物件型別、編碼、記憶體**、共享物件都有關係;乙個redisobject物件的大小為16位元組:

4bit+4bit+24bit+4byte+8byte=16byte。

redis沒有直接使用c字串(即以空字元』\0』結尾的字元陣列)作為預設的字串表示,而是使用了sds。

struct sdshdr ;
其中,,buf表示位元組陣列,用來儲存字串;len表示buf已使用的長度,free表示buf未使用的長度。

通過sds的結構可以看出,buf陣列的長度=free+len+1(其中1表示字串結尾的空字元);所以,乙個sds結構佔據的空間為:free所佔長度+len所佔長度+ buf陣列的長度=4+4+free+len+1=free+len+9。

free及len所佔長度指的是儲存具體數值所占用的空間,典型的空間換時間,降低了時間複雜度。

Redis記憶體模型

五 理解記憶體 1.記憶體消耗 1 物件記憶體 redis所有資料均採用keyvalue資料型別,每次建立鍵值對時,至少建立兩個型別物件 key物件和value物件,物件記憶體 sizeof keys sizeof values key物件均為字串,value物件包括 string hash lis...

Redis記憶體模型

3.4.1 refcount與共享物件 緩衝區溢位 使用c字串的api時,如果字串長度增加 如strcat操作 而忘記重新分配記憶體,很容易造成緩衝區的溢位 而sds由於記錄了長度,相應的api在可能造成緩衝區溢位時會自動重新分配記憶體,杜絕了緩衝區溢位。修改字串時記憶體的重分配 對於c字串,如果要...

redis記憶體模型

檢視記憶體info memory redis分配器分配的記憶體總量 位元組 used memory 24989816 redis分配器分配的記憶體總量 used memory human 23.83m redis程序佔據作業系統的記憶體 位元組 used memory rss 36409344 us...