基本数据结构
直接看官方说明就行了:
- Binary-safe strings.
- Lists: collections of string elements sorted according to the order of insertion. They are basically linked lists.
- Sets: collections of unique, unsorted string elements.
- Sorted sets, similar to Sets but where every string element is associated to a floating number value, called score.
The elements are always taken sorted by their score, so unlike Sets it is possible to retrieve a range of elements
(for example you may ask: give me the top 10, or the bottom 10). - Hashes, which are maps composed of fields associated with values. Both the field and the value are strings.
This is very similar to Ruby or Python hashes. - Bit arrays (or simply bitmaps): it is possible, using special commands, to handle String values like an arrayof bits:
you can set and clear individual bits, count all the bits set to 1, find the first set or unset bit, and so forth. - HyperLogLogs: this is a probabilistic data structure which is used in order to estimate the cardinality of a set.
Don't be scared, it is simpler than it seems... See later in the HyperLogLog section of this tutorial.
基本的命令熟悉即可,大致知道各个数据类型有那些相应的操作,具体的可以翻手册: commands
关键是对于各个数据类型的具体应用场景心中要有大致的概念。
各个数据类型常见的应用场景
- Lists: Lists are useful for a number of tasks,
- Remember the latest updates posted by users into a social network.
- Communication between processes, using a consumer-producer pattern.
- Sets: tags
- Sorted sets: rank
redis内部数据结构
SDS
redis使用自己封装的SDS作字符串表示(结构体里有free, len, buf字段,buf才是存数据用的), 相比c字符串,主要优势有:
- O(1)时间复杂度获取字符串长度(结构体里就有)
- 杜绝缓冲区溢出(会先检查free,不够就扩展)
- 减少修改字符串长度时所需的内存重分配次数(预分配和惰性释放)
- 二进制安全(不适用空字符串来判断长度)
- 兼容部分C字符串函数
struct sdshdr { // 记录buff数组中已使用字节的数量,等于SDS中保存字符串的长度 int len; // 记录buf数组中未使用字节的数量 int free; // 字节数组,用于保存字符串 char buf[]; };
链表
lists用双向链表实现,主要有以下特点:
- 节点带prev和next指针(listNode结构体有prev,next指针,value是存值的);表头prev和表尾next都是null,无环没有循环
- 链表带表头,表位指针和长度(list结构体带head,tail指针,len表示长度,还有dup,free,match函数)
- 多态,节点用void*指针存值,可以保存不同类型的值
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); // 节点值对比函数 void (*match) (void *ptr, void *key); }
字典
typedef struct dict { // 类型特定函数 dictType *type; // 私有数据, 和上面的字段一起为了多态字典设置 void *privdata; // 哈希表,一般只用ht[0],ht[1]在rehash的时候用 dictht ht[2]; // rehash索引,记录当前的进度,当rehash不在进行时,值尾-1 int rehashidx; } typedef struct dictht { // 哈希表数组, 其中的每个元素是指向dictEntry的指针,每个dictEntry保存一个键值对 dictEntry **table; // 哈希表大小 unsigned long size; // 哈希表大小掩码,用于计算索引值,总是等于size-1 unsigned logn sizemask; // 哈希表已有节点数量 unsigned long used; } typedef struct dictEntry { // 键 void *key; // 值 union{ void *val; uint64 u64; int64_t s64; } v; // 指向下个哈希表节点,行程链表 struct dictEntry *next }
redis哈希表使用链地址法(seperate chaining)来解决键冲突。因为哈希表数组中的每个元素都有next指针,可以构成一个单向链表。
哈希表根据负载因子(ht[0].used/ht[0].size)进行扩展或收缩,通过渐进式rehash来完成
(字典的rehashidx标记了上个完成的哈希数组的元素id,完成后加1下移,-1表示未有rehash行为)
跳跃表
sorted set底层实现之一。
typedef struct zskiplist { // 表头和表尾 struct zskiplistNode *header, *tail; // 节点数量 unsigned long length; // 层数最大的节点的层数 int level; } zskiplist; typedef struct zskiplistNode { // 后退指针 struct zskiplistNode *backward; // 分值,同一个跳跃表中可以相同。节点按分值大小排序,相同时按成员大小排序 double score; // 成员对象,同个跳跃表中必须唯一 robj *obj; // 层, 1-32的随机数 sturct zskiplistLevel { // 前进指针 struct zskiplistNode *forward; // 跨度 unsigned int span; } } zskiplistNode;
整数集合
typedef struct intset { // 编码方式 uint32_t encoding; // 集合包含的元素数量 uint32_t length; // 保存元素的数组,有序唯一。有需要的时候根据新加元素类型改变数组类型,即升级操作, // 好处是提升灵活性(不同类型整数放到同个集合中)和节约内存(有必要时才升级) int8_t constants[]; } intset;
对象
redis用对象来表示每个键值对的键和值, 会共享0到9999的字符串对象
typedef struct redisObject { // 类型 usigned type:4; // 编码 usigned encoding:4; // 指向底层实现数据结构的指针 void *ptr; // 引用计数 unsigned refcount; // 对象最后一次被命令程序访问的时间 unsigned lru:22; }
- REDIS_STRING
- REDIS_ENCODING_INT
- REDIS_ENCODING_EMBSTR
- REDIS_ENCODING_RAW
- REDIS_LIST
- REDIS_ENCODING_ZIPLIST
- REDIS_ENCODING_LINKEDLIST
- REDIS_HASH
- REDIS_ENCODING_ZIPLISH
- REDIS_ENCODING_HT
- REDIS_SET
- REDIS_ENCODING_INTSET
- REDIS_ENCODING_HT
- REDIS_ZSET
- REDIS_ENCODING_ZIPLIST
- REDIS_ENCODING_SKIPLIST
注:5.0的redis,list的底层实现只有quicklist了。
db
struct redisServer { ... // 数组,保存服务器中所有的数据库,用select命令选择连接的数据库; redisDb *db; // 服务器数据库数量; int dbnum; ... } typedef struct redisDb { ... // 数据库键空间,保存着数据库中所有的键值对,键是字符串对象,值是redis对象。 dict *dict; // 过期字典,保存着键的过期时间,可以通过expire, pexpire, expireat, pexpireat设置, persist移除,ttl确认剩余时间。 // redis通过惰性删除和定时删除来删除过期的键。 dict *expires; ... }
其他
- connection
- transaction
- pub/sub
- server
- cluster
- scripting
- geo
参考资料
- Redis设计与实现