- 基本数据类型
名称 | 数据类型(Type) | 说明 |
---|---|---|
简单动态字符串类 | string | redis中最基本的数据类型,一个key对应一个value,string类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象 |
链表 | list | list 说白了就是链表(redis 使用双端链表实现的 list),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除数据 |
字典 | hash | 是一个Map,指值本身又是一种键值对结构,如 value={{field1,value1},......fieldN,valueN}} |
集合 | set | 集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中 1. 不允许有重复的元素,2.集合中的元素是无序的,不能通过索引下标获取元素,3.支持集合间的操作,可以取多个集合取交集、并集、差集 |
有序集合 | zset | 有序集合和集合有着必然的联系,保留了集合不能有重复成员的特性,区别是,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据 |
- 数据类型底层编码结构图
-
数据库结构体源码 (redisDb、dict、dictht、dictEntry、redisObject 源码示意)
-
redisDb
Redis是内存数据库,除了需要redisObject对基础数据结构封装外,还需要一个结构体对数据库进行封装,用来管理数据库相关数据 和实现相关操作,这个结构体就是redisDb。
redisDb有两个重要属性——dict和expires,分别是键空间散列 表、过期时间散列表。dict保存了所有的键值对,expires保存了键的过期时间,像scan、move、sort等命令是对redisDb键空间散列表的操作,expire、persist等命令是对redisDb键的过期时间散列表的操作,具 体我们将在后面讲解,redisDb结构体定义如下
typedef struct redisDb { dict *dict; /* 键空间字典 */ dict *expires; /* key的超时时间字典 */ dict *blocking_keys; /* 阻塞的key */ dict *ready_keys; /* 准备好的key */ dict *watched_keys; /* 执行事务的key */ int id; /* 数据库ID */ long long avg_ttl; /* 平均生存时间,用于统计 */ list *defrag_later; /* 逐渐尝试逐个碎片整理的key列表*/ } redisDb;
属性 说明 *dict 键空间散列表,存放所有键值对 *expires 过期时间散列表,存放键的过期时间,注意dict和expires中的键都指向同一个键的sds *blocking_keys 处于阻塞状态的键和对应的client *ready_keys 解除阻塞状态的键和对应的client,与blocking_keys,属性相对,为了实现需要阻塞的命令设计 *watched_keys watch的键和对应的client,主要用于事务 id 数据库ID avg_ttl 数据库内所有键的平均生存时间 defrag_later 逐渐尝试逐个碎片整理的key列表 - dict
typedef struct dict { dictType *type; /*该字典对应的特定操作函数*/ void *privdata; /*该字典依赖的数据*/ dictht ht[2]; /*Hash表,键值对存储再此; 一个字典有两个哈希表*/ long rehashidx; /*rehash索引 rehashing not in progress if rehashidx == -1 */ unsigned long iterators; /*当前正在使用的迭代器数量/ */ } dict;
- dictType
typedef struct dictType { uint64_t (*hashFunction)(const void *key);/*该字典对应的Hash函数*/ void *(*keyDup)(void *privdata, const void *key);/*键对应的复制函数*/ void *(*valDup)(void *privdata, const void *obj);/*值对应的复制函数*/ int (*keyCompare)(void *privdata, const void *key1, const void *key2);/*键的比对函数*/ void (*keyDestructor)(void *privdata, void *key); /*键的销毁函数*/ void (*valDestructor)(void *privdata, void *obj); } dictType;/*值的销毁函数*/
- dictht
typedef struct dictht { dictEntry **table; // 指针数组,用于存储键值对 unsigned long size; // table数组的大小 unsigned long sizemask; //掩码 = size - 1 unsigned long used; //table数组已存元素个数,包含next单链表的数据 } dictht;
- dictEntry
typedef struct dictEntry { void *key; /*存储键*/ union { void *val; /*db.dict中的val*/ uint64_t u64; int64_t s64;/*db.expires中存储过期时间*/ double d; } v; /*封装成一个对象*/ struct dictEntry *next; /*当Hash冲突时,指向冲突的元素,形成单链表* } dictEntry;
-
redisObject
Redis主要的数据结构,为了便于操作和维护,Redis在此基础上封装了redisObject对象,其定义在server.h文件,redisObject根据type的不同可以分为字符串对象、列表对象、集合对 象、有序集合对象、散列表对象、模块对象和流对象
此外对象保存了数据底层存储所使用的编码,在存储数据时,Redis会自动选择合适的编码。对象还实现了引用计数,当程序不再使 用对象时,对象会自动释放
typedef struct redisObject { unsigned type:4; //type表示Redis对象的类型,占用4位 unsigned encoding:4; //encoding表示对象内部存储的编码,在一定条件下, 对象的编码可以在多个编码之间转化,长度占用4位 unsigned lru:LRU_BITS; //lru占用24位,当用于LRU时表示最后一次访问时间,当用 于LFU时,高16位记录分钟级别的访问时间,低8位记录访问频率0到 255,默认配置8位可表示最大100万访问频次 int refcount; // refcount表示对象被引用的LRU_BITS,当refcount为0时候,表示该对象不被任何对象引用,可进行垃圾回收 void *ptr;// ptr是指向具体数据的指针,比如一个字符串对象,该指针 指向存放数据sds的地址 } robj;
属性 说明 type #define OBJ_STRING 0 /* 字符串对象 / #define OBJ_LIST 1 / 列表对象 / #define OBJ_SET 2 / 集合对象 / #define OBJ_ZSET 3 / 有序集合对象 / #define OBJ_HASH 4 / 散列表对象 / #define OBJ_MODULE 5 / 模块对象 / #define OBJ_STREAM 6 / 流对象 */ encoding #define OBJ_ENCODING_RAW 0 /* Raw representation / #define OBJ_ENCODING_INT 1 / 编码为整数 / #define OBJ_ENCODING_HT 2 / 编码为散列表 / #define OBJ_ENCODING_ZIPMAP 3 / 编码为zipmap / #define OBJ_ENCODING_LINKEDLIST 4 / 不再使用:旧列表编码 / #define OBJ_ENCODING_ZIPLIST 5 / 编码为压缩列表 / #define OBJ_ENCODING_INTSET 6 / 编码为整数集合 / #define OBJ_ENCODING_SKIPLIST 7 / 编码为跳表 / #define OBJ_ENCODING_EMBSTR 8 / 编码为简短字符串 / #define OBJ_ENCODING_Quicklist 9 / 编码为快速链表 / #define OBJ_ENCODING_STREAM 10 / 编码为listpacks的基数树*/ -
-
数据库结构体图
总结
由Redis基础的数据结构,引出对基本数据类型的介绍
\