--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设计与实现》黄健宏