![b3ad2342ddbd7fde3c3e0d5d1181c8f8.png](https://i-blog.csdnimg.cn/blog_migrate/562177e928cd1a0ad3324f6e8f997fdc.jpeg)
一丶数据结构
简单的动态字符串
Redis的默认字符串类型为SDS。只会使用C字符串作为字面量(比如打印)。
struct
SDS遵循C字符串以空字符串结尾的惯例,保存空字符串的1字节空间不计入SDS的len属性里面。
优点:字符串的复杂度为O(1);len可直接返回长度。
杜绝缓冲区溢出;SDS的空间分配杜绝了溢出可能。
减少字符串修改带来的内存重分配次数;修改后SDS长度小于1M,分配和len同样大小的未使用空间;修改后大于1M,则每次分配1M空间。
二进制安全,可保存二进制数据;包含空字符串的特殊文本格式,会使C字符串误认为结束,是二进制不安全的。
兼容C字符串函数;可复用C字符串函数库。
链表
C语言没有链表的数据结构。Redis自己构建了链表的实现。
//链表节点
特性:
双端;链表节点带有prev和next指针,获取前后节点的复杂度为O(1)。
无环;表头节点的prev和表尾节点的next都指向null。
带表头指针和表尾指针。
带链表长度计数器。
多态;通过三个函数,可用于保存各种不同类型的值。
字典
C语言没有字典的数据结构。Redis自己构建了字典的实现。、
Redis的数据库就是用字典来实现的,也是哈希建的底层实现。
//哈希表
哈希算法:通过键值对的键计算出hash值与掩码做位与(&)得出索引值。为解决冲突,通过指针构成一个链表,采用头插法。redis使用链地址法解决哈希冲突。
rehash:为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表。在字典中维持一个rehashidx,值为0.每次对字典的操作,先在ht[0]上执行然后rehash到ht[1],rehashidx值增加一。随着时间的推移,ht[0]终将全部rehash到ht[1]中。这时将rehashidx置为-1。所有新增加的键值都会保存到ht[1]中
跳跃表
跳跃表是一种有序的数据结构,支持平均O(logN)和最坏O(N)的复杂度;大部分情况下跳跃表的效率和平衡树相媲美。
redis使用跳跃表作为有序集合键的底层实现。
//跳跃表节点
整数集合
整数集合(inset)是集合键的底层实现之一,当一个集合只包含整数值元素,且元素数量不多时,redis就会使用整数集合作为集合键的底层实现。
//整数集合
升级:当将一个新元素添加到整数集合里面,且比集合现有的元素类型都要长时,需要对集合先进行升级,然后再添加元素。(不支持降级,升级后会保持升级后数据类型)
1.根据新元素的类型扩展空间
2.将现有元素类型转换为新类型,并将现有元素放置到新位置上
3.添加新元素到底层数组
压缩列表
压缩列表(ziplist)是列表键和哈希键的底层实现之一。当包含少量列表项,且每个列表项是比较小的字符串时,redis就使用压缩列表来做列表键的底层实现。
压缩列表:
整个压缩列表占用大小 | 起始到结尾节点的字节数 | 节点数量 | 节点1 | 节点2 | 标记结尾 |
---|---|---|---|---|---|
zlbytes | zltail | zllen | entry1 | entry2 | zlend |
节点:
前一节点的长度(长度小于254字节,值的长度为1字节.长度大于等于254,值的长度为5字节) | 记录content保存数据的类型和长度 | 值 |
---|---|---|
previous_entry_length | encoding | content |
连锁更新:previous_entry_length字段的长度有1字节和5字节,若连续多个节点的长度为253,若其中一个节点的长度更新为254,则下一节点的previous_entry_length要重1字节变为5字节。引起连锁更新。
对象
redis并没有直接使用上面的数据结构来实现键值的数据库,而是基于这些数据结构创建一个对象系统。包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象
//对象
类型:
类型 | type值 | TYPE命令输出 |
---|---|---|
字符串 | REDIS_STRING | "string" |
列表 | REDIS_LIST | "list" |
哈希 | REDIS_HASH | "hash" |
集合 | REDIS_SET | "set" |
有序集合 | REDIS_ZSET | "zset" |
编码:
编码值 | 对应的数据结构 |
---|---|
REDIS_ENCODING_INT | long类型的整数 |
REDIS_ENCODING_ENBSTR | embstr编码的简单动态字符串 |
REDIS_ENCODING_RAW | 简单动态字符串 |
REDIS_ENCODING_HT | 字典 |
REDIS_ENCODING_LINKEDLIST | 双向链表 |
REDIS_ENCODING_ZIPLIST | 压缩列表 |
REDIS_ENCODING_INTSET | 整数集合 |
REDIS_ENCODING_SKIPLIST | 跳跃表和字典 |
不同的组合:
类型 | 编码 | 对象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 整数值字符串 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | embstr编码的简单动态字符串 |
REDIS_STRING | REDIS_ENCODING_RAW | 简单动态字符串 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 压缩列表实现的列表对象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 双向链表实现的列表对象 |
REDIS_HSHA | REDIS_ENCODING_ZIPLIST | 压缩列表实现的哈希对象 |
REDIS_HSHA | REDIS_ENCODING_HT | 字典实现的哈希对象 |
REDIS_SET | REDIS_ENCODING_INTSET | 整数集合实现的集合对象 |
REDIS_SET | REDIS_ENCODING_HT | 字典实现的集合对象 |
REDIS_SET | REDIS_ENCODING_ZIPLIST | 压缩列表实现的有序集合对象 |
REDIS_SET | REDIS_ENCODING_SKIPLIST | 跳跃表和字典实现的有序集合对象 |
为什么有序集合要使用跳跃表和字典实现?
字典优点:以O(1)的复杂度查找成员
跳跃表优点:范围型操作需排序,而跳跃表是按排序存储元素的
#可通过下面命令查看编码类型
OBJECT ENCODING key值