redis 数据结构
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
?
| redis對象 | redis 數(shù)據(jù)結(jié)構 |
| 字符串對象 | ?SDS(簡單動態(tài)字符串) |
| 列表對象 | ?壓縮列表(ziplist) 或 鏈表(linkedlist) |
| 哈希對象 | ?壓縮列表 或 字典 |
| 集合對象 | ?整數(shù)集合 或 字典 |
| 有序集合對象 | ?壓縮列表 或 跳躍表和字典 |
?
| REDIS_STRING | REDIS_ENCODING_INT | 使用整數(shù)值實現(xiàn)的字符串對象。 |
| REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用?embstr?編碼的簡單動態(tài)字符串實現(xiàn)的字符串對象。 |
| REDIS_STRING | REDIS_ENCODING_RAW | 使用簡單動態(tài)字符串實現(xiàn)的字符串對象。 |
| REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現(xiàn)的列表對象。 |
| REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用雙端鏈表實現(xiàn)的列表對象。 |
| REDIS_HASH | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現(xiàn)的哈希對象。 |
| REDIS_HASH | REDIS_ENCODING_HT | 使用字典實現(xiàn)的哈希對象。 |
| REDIS_SET | REDIS_ENCODING_INTSET | 使用整數(shù)集合實現(xiàn)的集合對象。 |
| REDIS_SET | REDIS_ENCODING_HT | 使用字典實現(xiàn)的集合對象。 |
| REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用壓縮列表實現(xiàn)的有序集合對象。 |
| REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳躍表和字典實現(xiàn)的有序集合對象。 |
?
REDIS_STRING
編碼raw結(jié)構
sds字符串?
?
struct sdshdr{
?? ?? //記錄 buf 數(shù)組中已使用字節(jié)的數(shù)量
int len;?//紀錄buf未使用字節(jié)的數(shù)量
int free
//存放字符串
char buf[];
};
作用 : 作為redis 的部分鍵 和 值
REDIS_LIST?
?
列表實現(xiàn)通過 鏈表和壓縮列表
linkedlist?
?
typedef struct listNode {// 前置節(jié)點struct listNode *prev;// 后置節(jié)點struct listNode *next;// 節(jié)點的值void *value;} listNode; typedef struct list {// 表頭節(jié)點listNode *head;// 表尾節(jié)點listNode *tail;// 鏈表所包含的節(jié)點數(shù)量unsigned long len;// 節(jié)點值復制函數(shù)void *(*dup)(void *ptr);// 節(jié)點值釋放函數(shù)void (*free)(void *ptr);// 節(jié)點值對比函數(shù)int (*match)(void *ptr, void *key);} list;作用 :鏈表為列表鍵 鏈表節(jié)點為值 ?實現(xiàn)redis?發(fā)布與訂閱, 慢查詢, 監(jiān)視器, 等等。
?
REDIS_HASH
哈希鍵的實現(xiàn) 字典 /壓縮列表
字典的實現(xiàn)
typedef struct dict {// 類型特定函數(shù)dictType *type;// 私有數(shù)據(jù)void *privdata;// 哈希表 rehash 時使用ht[1]dictht ht[2];// rehash 索引// 當 rehash 不在進行時,值為 -1int rehashidx; /* rehashing not in progress if rehashidx == -1 */} dict;?
哈希表的實現(xiàn)
typedef struct dictht {// 哈希表數(shù)組dictEntry **table;// 哈希表大小unsigned long size;// 哈希表大小掩碼,用于計算索引值// 總是等于 size - 1unsigned long sizemask;// 該哈希表已有節(jié)點的數(shù)量unsigned long used;} dictht;哈希表的節(jié)點
typedef struct dictEntry {// 鍵void *key;// 值union {void *val;uint64_t u64;int64_t s64;} v;// 指向下個哈希表節(jié)點,形成鏈表struct dictEntry *next;} dictEntry;通過鏈表解決沖突問題
負載因子為0.5 時擴張 小于0.1收縮
?
REDIS_SET ?
通過整數(shù)集合和字典實現(xiàn)
?
整數(shù)集合結(jié)構 只有小整數(shù) 才會在這里 其余都是在字典中實現(xiàn)
typedef struct intset {// 編碼方式uint32_t encoding;// 集合包含的元素數(shù)量uint32_t length;// 保存元素的數(shù)組int8_t contents[];} intset;REDIS_ZSET
?
有序集合通過跳躍表和字典實現(xiàn)或壓縮列表
有序集合的跳躍表和字典實現(xiàn)
跳躍表的實現(xiàn)
?
typedef struct zskiplist {// 表頭節(jié)點和表尾節(jié)點struct zskiplistNode *header, *tail;// 表中節(jié)點的數(shù)量unsigned long length;// 表中層數(shù)最大的節(jié)點的層數(shù)int level;} zskiplist;跳躍表的節(jié)點實現(xiàn)
typedef struct zskiplistNode {// 后退指針struct zskiplistNode *backward;// 分值 double 類型的浮點數(shù), 跳躍表中的所有節(jié)點都按分值從小到大來排序double score;// 成員對象 指向sds對象 值robj *obj;// 層 層高范圍1-32 第一層level[0]struct zskiplistLevel {// 前進指針 指向當前層的下一個節(jié)點struct zskiplistNode *forward;// 跨度 紀錄與同層下一節(jié)點之間的距離unsigned int span;} level[];} zskiplistNode;?
有序集合的實現(xiàn)
typedef struct zset {zskiplist *zsl; // 跳躍表dict *dict; // 字典} zset;zset?結(jié)構中的?dict?字典為有序集合創(chuàng)建了一個從成員到分值的映射, 字典中的每個鍵值對都保存了一個集合元素: 字典的鍵保存了元素的成員, 而字典的值則保存了元素的分值。 通過這個字典, 程序可以用?O(1)?復雜度查找給定成員的分值,?ZSCORE?命令就是根據(jù)這一特性實現(xiàn)的, 而很多其他有序集合命令都在實現(xiàn)的內(nèi)部用到了這一特性。
為什么有序集合需要同時使用跳躍表和字典來實現(xiàn)?
在理論上來說, 有序集合可以單獨使用字典或者跳躍表的其中一種數(shù)據(jù)結(jié)構來實現(xiàn), 但無論單獨使用字典還是跳躍表, 在性能上對比起同時使用字典和跳躍表都會有所降低。
舉個例子, 如果我們只使用字典來實現(xiàn)有序集合, 那么雖然以?O(1)?復雜度查找成員的分值這一特性會被保留, 但是, 因為字典以無序的方式來保存集合元素, 所以每次在執(zhí)行范圍型操作 —— 比如?ZRANK?、?ZRANGE?等命令時, 程序都需要對字典保存的所有元素進行排序, 完成這種排序需要至少?O(N \log N)?時間復雜度, 以及額外的?O(N)?內(nèi)存空間 (因為要創(chuàng)建一個數(shù)組來保存排序后的元素)。
另一方面, 如果我們只使用跳躍表來實現(xiàn)有序集合, 那么跳躍表執(zhí)行范圍型操作的所有優(yōu)點都會被保留, 但因為沒有了字典, 所以根據(jù)成員查找分值這一操作的復雜度將從?O(1)?上升為?O(\log N)?。
因為以上原因, 為了讓有序集合的查找和范圍型操作都盡可能快地執(zhí)行, Redis 選擇了同時使用字典和跳躍表兩種數(shù)據(jù)結(jié)構來實現(xiàn)有序集合。
參考文獻 《redis設計與實現(xiàn)》
?
轉(zhuǎn)載于:https://my.oschina.net/haloooooo/blog/872961
總結(jié)
以上是生活随笔為你收集整理的redis 数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。