--html
Redis中每一個鍵值對都是由對象組成:java
redis官方網站中對其數據類型的簡單介紹: An introduction to Redis data types and abstractions 摘抄一段關於redis key的介紹:redis
Redis keys Redis keys are binary safe, this means that you can use any binary sequence as a key, from a string like "foo" to the content of a JPEG file. The empty string is also a valid key. A few other rules about keys:數組
在redis源碼中,對象的數據結構定義在redis.h文件中數據結構
#define REDIS_LRU_BITS 24 typedef struct redisObject { // 類型 unsigned type:4; // 編碼 unsigned encoding:4; // 對象最後一次被訪問的時間 unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */ // 引用計數 int refcount; // 指向實際值的指針 void *ptr; }
下面分別介紹如下對象中定義的屬性定義:less
// 對象類型 #define REDIS_STRING 0 #define REDIS_LIST 1 #define REDIS_SET 2 #define REDIS_ZSET 3 #define REDIS_HASH 4
// 對象編碼 #define REDIS_ENCODING_RAW 0 /* Raw representation */ #define REDIS_ENCODING_INT 1 /* Encoded as integer */ #define REDIS_ENCODING_HT 2 /* Encoded as hash table */ #define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */ #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ #define REDIS_ENCODING_INTSET 6 /* Encoded as intset */ #define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ #define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
盜取一張圖(懶的畫圖): 各類對象的建立能夠參考redis源碼中的object.c文件,如: 根據傳入的整數型,建立一個字符串:ide
/* * 根據傳入的整數值,建立一個字符串對象 * * 這個字符串的對象保存的能夠是 INT 編碼的 long 值, * 也能夠是 RAW 編碼的、被轉換成字符串的 long long 值。 */ robj *createStringObjectFromLongLong(long long value) { robj *o; // value 的大小符合 REDIS 共享整數的範圍 // 那麼返回一個共享對象 if (value >= 0 && value < REDIS_SHARED_INTEGERS) { incrRefCount(shared.integers[value]); o = shared.integers[value]; // 不符合共享範圍,建立一個新的整數對象 } else { // 值能夠用 long 類型保存, // 建立一個 REDIS_ENCODING_INT 編碼的字符串對象 if (value >= LONG_MIN && value <= LONG_MAX) { o = createObject(REDIS_STRING, NULL); o->encoding = REDIS_ENCODING_INT; o->ptr = (void*)((long)value); // 值不能用 long 類型保存(long long 類型),將值轉換爲字符串, // 並建立一個 REDIS_ENCODING_RAW 的字符串對象來保存值 } else { o = createObject(REDIS_STRING,sdsfromlonglong(value)); } } return o; }
線面簡單看看基本類型type對應的底層數據結構:函數
sting在redis底層對應三種編碼方式,兩種數據結構。 若是一個字符串內容能夠轉成long,那麼編碼方式爲int,底層數據結構爲int. 若是普通字符串對象的長度小於39字節,就用embstr對象。不然用的raw對象,底層數據結構爲簡單動態字符串。post
/* Create a string object with EMBSTR encoding if it is smaller than * REIDS_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is * used. * * The current limit of 39 is chosen so that the biggest string object * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */ #define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39 robj *createStringObject(char *ptr, size_t len) { if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else return createRawStringObject(ptr,len); }
簡單動態字符串(simple dynamic string)的數據結構爲:網站
/* * 保存字符串對象的結構 */ struct sdshdr { // buf 中已佔用空間的長度 int len; // buf 中剩餘可用空間的長度 int free; // 數據空間 char buf[]; };
有兩種編碼實現,鏈表linkedlist和壓縮列表ziplist,噹噹list元素少且元素內容長度不大時,使用ziplist,不然使用linkedlist.
/* Use a real list when there are too many entries * * 根據節點數,建立對象的編碼 */ if (len > server.list_max_ziplist_entries) { o = createListObject(); } else { o = createZiplistObject(); } /* * 建立一個 LINKEDLIST 編碼的列表對象 */ robj *createListObject(void) { list *l = listCreate(); robj *o = createObject(REDIS_LIST,l); listSetFreeMethod(l,decrRefCountVoid); o->encoding = REDIS_ENCODING_LINKEDLIST; return o; } /* * 建立一個 ZIPLIST 編碼的列表對象 */ robj *createZiplistObject(void) { unsigned char *zl = ziplistNew(); robj *o = createObject(REDIS_LIST,zl); o->encoding = REDIS_ENCODING_ZIPLIST; return o; }
#####鏈表linkedlist 其底層數據結構list位於adlist.h中:
/* * 雙端鏈表節點 */ typedef struct listNode { // 前置節點 struct listNode *prev; // 後置節點 struct listNode *next; // 節點的值 void *value; } listNode; /* * 雙端鏈表結構 */ typedef struct list { // 表頭節點 listNode *head; // 表尾節點 listNode *tail; // 節點值複製函數 void *(*dup)(void *ptr); // 節點值釋放函數 void (*free)(void *ptr); // 節點值對比函數 int (*match)(void *ptr, void *key); // 鏈表所包含的節點數量 unsigned long len; } list;
相似數組,可是每一個節點存儲的數據大小不一樣,節點上有length屬性。
有兩種數據結構實現,壓縮列表ziplist和字典dict.
至關於java中的HashMap。解決hash衝突使用的是鏈表法,好像沒有上升到紅黑樹。
若是是整數類型,直接使用整數集合intset,若是不是,就用字典,和java的set同樣。
有序的set,元素個數少且不大,就用壓縮列表ziplist,不然就用跳躍表skiplist.
跳躍表(skiplist)是一種有序數據結構,它經過在每一個節點中維持多個指向其餘節點的指針,從而達到快速訪問節點的目的。 跳躍表是一種隨機化的數據,跳躍表以有序的方式在層次化的鏈表中保存元素。 定義位於redis.h中。
/* ZSETs use a specialized version of Skiplists */ /* * 跳躍表節點 */ typedef struct zskiplistNode { // 成員對象 robj *obj; // 分值 double score; // 後退指針 struct zskiplistNode *backward; // 層 struct zskiplistLevel { // 前進指針 struct zskiplistNode *forward; // 跨度 unsigned int span; } level[]; } zskiplistNode; /* * 跳躍表 */ typedef struct zskiplist { // 表頭節點和表尾節點 struct zskiplistNode *header, *tail; // 表中節點的數量 unsigned long length; // 表中層數最大的節點的層數 int level; } zskiplist;
深刻淺出Redis-redis底層數據結構(上) 深刻淺出Redis-redis底層數據結構(下) Redis基本類型及其數據結構 Redis的五種對象類型及其底層實現 Redis-基本數據類型與內部存儲結構 redis的五種基本數據類型及其內部實現 《Redis設計與實現》黃健宏