比照另一个驰名的缓存中间件 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,其它类型的对象同理。