redis底层数据结构简述
2019獨角獸企業重金招聘Python工程師標準>>>
redis的數據庫對象有五種,分別是字符串對象(key-value),列表對象(list),哈希對象(hash),集合對象(set),有序集合(sort?set)。
這些數據對象來自于底層數據類型的實現,這些數據類型分別為簡單動態字符串,鏈表,字典,跳躍表,整數集合,壓縮列表,對象。
以下是redisObject和底層數據結構的關系
簡單動態字符串(SDS)
redis的鍵(KEY)由簡單動態字符串實現,字符串對象(key-value)也是由簡單動態字符串實現的。而簡單動態字符串是由C實現的,它的結構如下
struct sdshr{//記錄buf中已經使用的字節數量unsigned int len;//記錄buf中未使用的字節數量unsigned int free;//字節數組,存儲字符串char buf[]; }在redis3.2版本后,SDS的結構發生了變化,有多種數據結構,根據情況使用
//字符串長度小于32 Byte struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 記錄當前字節數組的屬性,到底是哪個SDS結構 */char buf[];/* 保存字符串真正的值 */ }; //字符串長度小于256 Byte,大于32 Byte struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* 記錄當前數組的長度 */uint8_t alloc; /* 記錄了當前字節數組總共分配的內存大小 */unsigned char flags; /* 記錄當前字節數組的屬性,到底是哪個SDS結構 */char buf[];/* 保存字符串真正的值 */ }; //字符串長度小于65536 Byte (64KB),大于256 Byte struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* 記錄當前數組的長度 */uint16_t alloc; /* 記錄了當前字節數組總共分配的內存大小 */unsigned char flags; /* 記錄當前字節數組的屬性,到底是哪個SDS結構 */char buf[];/* 保存字符串真正的值 */ }; //字符串長度小于4294967296 Byte (4GB),大于65536 Byte struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* 記錄當前數組的長度 */uint32_t alloc; /* 記錄了當前字節數組總共分配的內存大小 */unsigned char flags; /* 記錄當前字節數組的屬性,到底是哪個SDS結構 */char buf[];/* 保存字符串真正的值 */ }; //字符串長度大于4294967296 Byte (4GB) struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* 記錄當前數組的長度 */uint64_t alloc; /* 記錄了當前字節數組總共分配的內存大小 */unsigned char flags; /* 記錄當前字節數組的屬性,到底是哪個SDS結構 */char buf[];/* 保存字符串真正的值 */ };鏈表
鏈表是redis對象列表(list)的一種實現。當列表中元素數量比較多,或元素中字符串數量比較大時,就會使用鏈表結構。鏈表方便順序查詢,同時也方便插入和刪除。
鏈表由listNode和list組成,其結構如下
typedef struct listNode{struct listNode *prev;//前一個節點struct listNode * next;//后一個節點void * value;//節點值 } typedef struct list{//頭節點listNode * head;//尾節點listNode * tail;//長度unsigned long len;//復制函數void *(*dup) (void *ptr);//釋放函數void (*free) (void *ptr);//對比函數int (*match)(void *ptr, void *key); }結構圖如下:
字典
字典可以用來保存鍵值對,字典的結構和java的hashMap結構相似,采用hash算法保存key。字典由字典,哈希表,哈希表節點實現。其結構如下:
/** 哈希表節點*/ typedef struct dictEntry {// 鍵void *key;// 值,可以是三種形式:指針,8字節字符,8字節整數union {void *val;uint64_t u64;int64_t s64;} v;//指向下個哈希表節點,形成鏈表(如下hash沖突,會形成鏈表)struct dictEntry *next; } /** 哈希表*/ typedef struct dictht {// 哈希表數組// 里面存儲dictEntrydictEntry **table;// 哈希表大小unsigned long size;// 哈希表大小掩碼,用于計算索引值// 總是等于 size - 1,index = hash & sizemask// 這樣所有計算得出的hash值都可以對應于table的索引unsigned long sizemask;// 該哈希表已有節點的數量unsigned long used; } /** 字典*/ typedef struct dict {// 類型特定函數,type和privdata是為了多態字典所設置的dictType *type;// 私有數據void *privdata;// 哈希表,每個字典包含兩個table// ht[0]是平時使用的哈希表,ht[1]是rehash時使用的哈希表dictht ht[2];// rehash 索引標識// 當 rehash 不在進行時,值為 -1int rehashidx; }字典結構圖如下:
跳躍表
跳躍表是一種有序的數據結構,它通過score進行排序。跳躍表有層級的概念,每個跳躍表節點有多層,每個層級會按順序指向之后若干節點的對應層級。這是為了便于查詢,通過層級查詢節點,會比按score順序依次查詢要快很多。節點和鏈表的結構如下:
typedef struct zskiplistNode{//層struct zskiplistLevel{//前進指針struct zskiplistNode *forward;//跨度unsigned int span;} level[];//后退指針struct zskiplistNode *backward;//分值double score;//成員對象robj *obj; } typedef struct zskiplist {//表頭節點和表尾節點struct zskiplistNode *header,*tail;//表中節點數量unsigned long length;//表中層數最大的節點的層數int level; }結構圖如下:
整數集合
當一個集合的元素數量不大,且類型都為整數時,redis就會使用整數集合進行存儲。它的結構如下:
typedef struct intset{//編碼方式uint32_t enconding;// 集合包含的元素數量uint32_t length;//保存元素的數組 int8_t contents[]; }壓縮列表
壓縮列表是列表對象和哈希對象的實現方式之一。當一個列表的元素數量不多,且值為整數和不長的字符串,這時redis會使用壓縮列表。同樣如果一個哈希對象的key和value的值數量不多,且為整數和不長的字符串時,redis也會使用壓縮列表
?
參考資料:
https://www.cnblogs.com/jaycekon/p/6227442.html
https://www.cnblogs.com/jaycekon/p/6277653.html
轉載于:https://my.oschina.net/u/241670/blog/3058326
總結
以上是生活随笔為你收集整理的redis底层数据结构简述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kibana 创建索引 POST 403
- 下一篇: Python多线程原理与实现