天天看點

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

文章目錄

  • 1 redis 存儲結構
    • 1.1 redis 存儲結構大緻架構
    • 1.3 部分的redis源碼展示說明
  • 2 redis 存儲轉換
  • 3 redis的底層資料結構描述
    • 3.1 string
      • 3.1.1 int
      • 3.1.2 raw
      • 3.1.3 embstr
    • 3.2 list
      • 3.2.1 quicklist 雙向連結清單
      • 3.2.2 ziplist 壓縮清單
    • 3.3 hash
      • 3.3.1 dict(字典)
      • 3.3.2 壓縮清單
    • 3.4 set
      • 3.4.1 insert 整形數組
      • 3.4.2 dict 字典
    • 3.5 zset
      • 3.5.1 skiplist 跳表(後期會專門出一篇部落格介紹跳表結構)
      • 3.5.2 ziplist

1 redis 存儲結構

1.1 redis 存儲結構大緻架構

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

1.3 部分的redis源碼展示說明

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

redis中資料庫的結構定義

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

16個資料庫由一個資料庫對象指針管理,在redis-server的時候,dbnum預設值是16

2 redis 存儲轉換

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

此圖已經概括了redis中五種資料類型的全部底層資料結構的劃分和存儲轉換

3 redis的底層資料結構描述

3.1 string

3.1.1 int

字元串長度小于等于20 ,并且能夠轉成整數。

string 資料類型有一個位圖的功能,但是存儲位圖資料用的是raw 或者是embstr,原因是因為 raw 和embstr 是sds動态字元串,能夠節約記憶體。當然int 是4個位元組也是可以用作32位的位圖,但是其大小固定比較單一。

3.1.2 raw

raw 也是string的底層資料結構,當字元串的長度大于44時,底層使用raw結構,需要配置設定兩次記憶體空間(分别為 Redis Object 和 SDS 配置設定空間)。

3.1.3 embstr

當字元串長度小于44時,底層使用

隻配置設定一次記憶體空間(因為 Redis Object 和 SDS 是連續的)。

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述
typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). */
    int refcount;
    void *ptr;
} robj;
struct __attribute__ ((__packed__)) hisdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
           

當位元組數小于44時,配置設定的大小一直都是64個位元組

sizeof(struct redisObject) = 16;

sizeof(hisdshdr8) = 3;

還有一個\0 一個位元組

64 - sizeof(struct redisObject) - sizeof(hisdshdr8) -sizeof(“\0”) =44;

是以44 作為raw和embstr的分界點。

3.2 list

3.2.1 quicklist 雙向連結清單

這個不做多個解釋

3.2.2 ziplist 壓縮清單

這個在list隻是間接的使用

ziplist壓縮清單詳情

ziplist存儲是連續的記憶體空間,可以做壓縮。當設計計算時,ziplist明顯會比雙向連結清單的指針檢索慢,是以ziplist是犧牲時間換取空間的結構。list的底層采取的是壓縮清單加雙向連結清單的存儲結構,quicklist 為了存儲更多的資料,會對每個 quicklistNode 節點進行壓縮,這樣就可以有效的存儲更多的消息隊列或者文章的資料了。

當實作為雙向連結清單時,節點會有pre和next指針,每一個指針占8個位元組。而ziplist的entry中,用previous_entry_length儲存上一個entry的長度,當上一個entry長度小于等于263位元組時,previous_entry_length隻占一個位元組;大于263位元組時,previous_entry_length占5個位元組,并且ziplist存儲是連續的記憶體空間,可以做壓縮。當設計計算時,ziplist明顯會比雙向連結清單的指針檢索慢,是以ziplist是犧牲時間換取空間的結構

清單的典型使用場景有以下兩個:

消息隊列:清單類型可以使用 rpush 實作先進先出的功能,同時又可以使用 lpop 輕松的彈出(查詢并删除)第一個元素,是以清單類型可以用來實作消息隊列;

文章清單:對于部落格站點來說,當使用者和文章都越來越多時,為了加快程式的響應速度,我們可以把使用者自己的文章存入到 List 中,因為 List 是有序的結構,是以這樣又可以完美的實作分頁功能,進而加速了程式的響應速度。

Redis存儲結構描述1 redis 存儲結構2 redis 存儲轉換3 redis的底層資料結構描述

zlbytes:壓縮清單位元組長度,占 4 位元組;

zltail:壓縮清單尾元素相對于起始元素位址的偏移量,占 4 位元組;

zllen:壓縮清單的元素個數;

entryX:壓縮清單存儲的所有元素,可以是位元組數組或者是整數;

zlend:壓縮清單的結尾,占 1 位元組。

3.3 hash

3.3.1 dict(字典)

typedef struct dict {
    dictEntry **table;
    dictType *type;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
    void *privdata;
} dict;
           

table :hash指針數組

type: 是以dictType通過函數指針的方式,将不同資料類型的操作都封裝起來。從面相對象的角度來看,可以把dictType當成dict中各種資料類型相關操作的interface,各個資料類型隻需要實作其對應的資料操作就行

size:hash 數組的大小 通常是2的n次方

sizemask:size-1 一般用作&

used:已經存儲的資料個數

其中dictEntry就是對dict中每對key-value的封裝,除了具體的key-value,其還包含一些其他資訊,具體如下:

typedef struct dictEntry {
    void *key;
    union {   // dictEntry在不同用途時存儲不同的資料 
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next; // hash沖突時開鍊,單連結清單的next指針 
} dictEntry;

           

3.3.2 壓縮清單

上面已經講過。當hash的資料結構中位元組數量大于等于512時且字元串長度小于等于64,hash的資料類型才會用壓縮清單這個資料結構。

3.4 set

3.4.1 insert 整形數組

元素都為整數且節點數量小于等于512時用整形數組

3.4.2 dict 字典

元素有一個不為整數 或者節點數量大于512 用dict

3.5 zset

3.5.1 skiplist 跳表(後期會專門出一篇部落格介紹跳表結構)

節點數量大于128 或者字元串長度大于一64

3.5.2 ziplist

節點數量小于128且字元串長度小于64