比照另一个驰名的缓存中间件memcached,redis提供了更加丰盛的数据结构和命令,它反对基于列表、汇合、哈希表等多种数据结构。这些构造在redis中是由6种底层数据结构来实现:

  • 简略动静字符串
  • (SDS)
  • 链表
  • 字典
  • 跳跃表
  • 整数
  • 汇合
  • 压缩列表

SDS

用来保留redis数据库中的字符串,它是一个构造体:

构造体中的三个属性别离用来示意已应用的字节数量、未应用的字节数量、字节数组,redis之所以设计这个构造而不应用C语言中的字符串,是因为SDS构造相比C语言中的字符串有如下长处:

记录了字符串的长度,执行strlen操作时,复杂度为O(1),而一般字符串为O(n)。SDS采纳事后调配和惰性开释的优化策略,缩小重新分配空间的次数,其中有free字段记录未应用空间字节数。二进制平安,除了能够存储字符还能够存储任意二进制。SDS操作函数会主动查看空间是否足够并且空间有余时主动扩大空间,从而避免内存溢出。

链表

用来存储链表构造数据,它被用来实现SADD等汇合命令:

字典

字典在Redis中利用十分宽泛,Redis数据库自身就是应用字典来作为底层实现的,比方咱们执行命令:SET msg "hello world",redis就会在数据库中创立一个键为msg值为"hello world"的字典。

字典在实现上蕴含两个hash表,惯例状态下,只有第一个hash表存储数据,当产生rehash时,会给第二个hash表调配空间,并且把第一个hash表中的数据拷贝到第二个hash表中。如果hash表中的数据量比拟大时,会采纳渐进式rehash,分屡次实现,字典中有个rehashindex字段记录rehash进度(如果以后未进行rehash值为-1),这样的话在字典中查问数据时,可能会查找两个hash表,先查第一个表,如果查不到再查第二个,然而新增的数据都会增加到第二个hash表中,产生rehash之后会由第二hash表负责查问客户端申请数据。当服务器正在执行BGSAVE、BGREWRITEAOF等耗CPU的命令时,会尽量避免rehash操作。

跳跃表

redis实现了一个跳跃表构造,跳跃表被用来实现缓存中的有序汇合如ZADD等命令。

整数汇合

当汇合中只蕴含整数时,并且汇合中的元素数量不多时,redis会采纳整数汇合当作底层实现。

其中contents中的元素有可能是16、32、64字节,redis只会调配适合的内存,比方以后增加的时16位的整数,那么只会给contents元素调配16字节,后续往数组中再次增加16字节以上的整数时,会给该数组降级重新分配32或64字节内存,数组只能降级不能降级,能从16字节降级到32或64字节,然而不能从64字节降级到16或32字节。

压缩列表

当列表、汇合、hash表、有序汇合等构造中的元素数量小于某个阀值,redis会采纳压缩列表当作这些构造的底层实现,目标是为了节俭内存,压缩列表蕴含了下列各个组成部分:

zlbytes 4字节,纪录整个压缩列表占用的内存字节数:在对压缩列表进行内存重调配,或计算zlend时应用。zltail 4字节,纪录压缩列表表尾节点间隔压缩列表的起始地址有多少个字节,通过这个偏移量程序能够毋庸遍历整个压缩列表就能够确定表尾节点的地址。zllen 2字节,纪录压缩列表蕴含的节点数量,当属性值等于UINT16_MAX时,结点的实在数量须要遍历整个压缩列表能力计算得出。entryX,列表节点,长度由结点中的内存结点,结点中有个字段previous_entry_length记录了前一个几点的长度,当结点的长度在254左右时,对某结点的批改可能会引发所有结点的连锁更新。

压缩列表会节约内存,然而拜访或批改构造中的元素时会损失一些性能,所以当元素数量或者元素大小超过了某个阀值之后会对值对象进行编码转换,转换成汇合、hash表、有序汇合等构造,并从新分配内存。

对象

Redis并没有间接应用下面那些数据结构来实现键值对数据库,而是在这些数据接口的根底上创立了一个对象零碎,每次在Redis数据库中新创建一个键值对时,至多会创立两个对象,一个键对象,一个值对象。每个对象都蕴含指定的类型和编码。

对象类型

对象的type属性设置,能够通过TYPE命令来输入对象的类型,对象有上面几种类型:

字符串对象:类型常量为REDIS_STRING,输入值string。列表对象:类型常量为REDIS_LIST,输入值list。哈希对象:类型常量为REDIS_HASH,输入值hash。汇合对象:类型常量为REDIS_SET,输入值hash。有序汇合表对象:类型常量为REDIS_ZSET,输入值zset。对象编码

对象的encoding属性设置,能够通过OBJECT ENCODING命令查看对象的编码,对象有上面几种编码:

long类型整数,REDIS_ENCODING_INT,输入intembstr编码的SDS,REDIS_ENCODING_EMBSTR,输入embstr。embstr编码是专门用于保留短字符串的一种优化编码方式,跟失常的字符编码相比,字符编码会调用两次内存调配函数来别离创立redisObject和sdshdr构造,而embstr编码则通过调用一次内存调配函数来调配一块间断的空间,空间中一次蕴含redisObject和sdshdr两个构造SDS,REDIS_ENCODING_RAW,输入raw字典,REDIS_ENCODING_HT,输入hashtable双端链表,REDIS_ENCODING_LINKEDLIST,输入linkedlist压缩列表,REDIS_ENCODING_ZIPLIST,输入ziplist整数汇合REDIS_ENCODING_INISET,输入intset跳跃表和字典,REDIS_ENCODING_SKIPLIST,输入skiplist每种类型的对象至多应用了两种不同的编码,在不同的条件下redis会对对象进行编码转换,比方如果对象保留的全部都是整数,那么他的编码是int,然而当执行了一些命令之后对象中存储的曾经不全副是整数了,那么会把该对象的编码从int变为raw,其它类型的对象同理。