[关闭]
@Alpacadh 2022-09-18T16:58:34.000000Z 字数 5795 阅读 233

数据结构

Redis


0、RedisObject

0.1 、基本概念

0.2、优点

0.3 代码结构

typedef struct redisObject{

//类型

unsigned type:4;

//编码

unsigned encoding:4;

//对象最后一次被访问的时间

unsigned lru:REDIS_LRU_BITS

//引用计数

int refcount

//指向底层实现数据结构的指针

void *ptr;

….. 

}

1、String

1.1 SDS 简单动态字符串

1.2 两种编码方式

1.2.1 embstr

1.2.2 raw

2、List 链表

2.1 基本结构

2.2 特性

①、双端:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。

②、无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 结束。  

③、带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。

④、多态:链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值。

3、字典

3.1 基本结构

key 用来保存键,val 属性用来保存值,值可以是一个指针,也可以是uint64_t整数,也可以是int64_t整数。

注意这里还有一个指向下一个哈希表节点的指针,我们知道哈希表最大的问题是存在哈希冲突,如何解决哈希冲突,有开放地址法和链地址法。这里采用的便是链地址法,通过next这个指针可以将多个哈希值相同的键值对连接在一起,用来解决哈希冲突

3.2 特性

**①、哈希算法:**Redis计算哈希值和索引值方法如下:

1

2

3

4

②、解决哈希冲突:这个问题上面我们介绍了,方法是链地址法。通过字典里面的 *next 指针指向下一个具有相同索引值的哈希表节点。

③、扩容和收缩:当哈希表保存的键值对太多或者太少时,就要通过 rerehash(重新散列)来对哈希表进行相应的扩展或者收缩。具体步骤:

1、如果执行扩展操作,会基于原哈希表创建一个大小等于 ht[0].used*2n 的哈希表(也就是每次扩展都是根据原哈希表已使用的空间扩大一倍创建另一个哈希表)。相反如果执行的是收缩操作,每次收缩是根据已使用空间缩小一倍创建一个新的哈希表。

2、重新利用上面的哈希算法,计算索引值,然后将键值对放到新的哈希表位置上。

3、所有键值对都迁徙完毕后,释放原哈希表的内存空间。

④、触发扩容的条件:

1、服务器目前没有执行 BGSAVE 命令或者 BGREWRITEAOF 命令,并且负载因子大于等于1。

2、服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令,并且负载因子大于等于5。

ps:负载因子 = 哈希表已保存节点数量 / 哈希表大小。

⑤、渐近式 rehash

什么叫渐进式 rehash?也就是说扩容和收缩操作不是一次性、集中式完成的,而是分多次、渐进式完成的。如果保存在Redis中的键值对只有几个几十个,那么 rehash 操作可以瞬间完成,但是如果键值对有几百万,几千万甚至几亿,那么要一次性的进行 rehash,势必会造成Redis一段时间内不能进行别的操作。所以Redis采用渐进式 rehash,这样在进行渐进式rehash期间,字典的删除查找更新等操作可能会在两个哈希表上进行,第一个哈希表没有找到,就会去第二个哈希表上进行查找。但是进行 增加操作,一定是在新的哈希表上进行的。

4、zset

zset 是 Redis 中一个非常重要的数据结构,其底层是基于跳表(skip list) 实现的。

4.1 底层数据结构-跳表

4.2 特点

5、intset

5.1 特点

6、压缩列表

6.1 特点

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注