Redis数据结构底层原理

目录

一、底层结构

1、SDS

2、intSet

3、Dict

4、ziplist

5、SkipList

二、Redis数据结构原理

1、string

2、set

3、zset

4、Hash


一、底层结构

1、SDS

SDS是可见字符串,没有直接用c语言的字符串,因为c长度要通过运算得到,非二进制安全(读到默认有个符号来判断是否结束,那么如果中间有个字符故意搞这个符号,他也会判断为结束了,所以非二进制安全),不可修改(他是保存到常量池的,一旦保存不能修改)

SDS是个结构体,有len代表长度,alloc代表总的字节数(申请内存的字节数),flags来控制头大小,以及一个char的数组。他读取的时候就不会读结尾标识符了,因为他有len字段所以方便很多,所以他是二进制安全的,而且需要获取长度也不需要遍历,他还可以动态变化和扩容的,他当要加新东西的时候,扩容如果小于1m就会变为原来长度的两倍+1,如果大于1m就会扩展后新字符串长度+1m+1,来预分配,因为分配内存很耗费性能的,因为要切换到内核去操作,所以提前先分配多一些。

2、intSet

intSet是redis中set集合实现方式之一,基于整数数组来实现,并且具备长度可变、有序等特征

他是个结构体存3个属性,1是编码方式2字节、4字节、8字节这种short、int、long的,2是length长度,3是整数数组,保存集合数据(他通过这3个属性可以快速定位,比如说2字节的short,那么长度说2的话,直接2*2直接可以定位到具体的元素,如果说4字节就是2*4了,就算没到也会填满4字节的,方便数组角标进行寻找,假如突然来个大的超过了原本的4字节,就会动态升级,他说倒叙升级的,全部升级为8字节的,升级编码方式到合适的大小)他插入的时候说通过二分查找来查找应该插入到哪个位置,从而保证有序

3、Dict

Dict是key-value的结构,他是由哈希表,哈希节点和字典组成。他的3个属性,第一个属性就是table,第二个属性是哈希表大小,第三个属性是size-1(用来&的应该),第四个是entry的个数。当put的时候就会算出hash值然后&上第三个属性size-1。他也有负载因子,当超过了阈值就会进行扩容,目的是为了减少hash冲突,但是redis是单线程的,所以他为了不影响主线程用的是渐进式rehash的方式扩容,他是每次做增删改查的时候都检查下是否在rehash,如果在就给他移动一个entry到新的数组。然后rehash的进度++,新增操作是直接插入到新数组,其他操作修改删除查询都要看两个数组,直到rehash结束才只用看一个数组。

4、ziplist

Ziplist压缩列表是特殊的双端链表,连续内存组成,可以在任意一端压入或弹出,并且操作时间复杂度是01,他头和尾字节数是固定的,中间每个元素是可以动态调整的,就不用像之前那样每个固定的需要填充占更多空间,每个entry要怎么定位呢既然不是固定的大小,所以entry存了前一个节点的长度。他通过这种记录前一个节点的长度的方式来代替指针,因为指针占用内存是很大的,他这种只需要一个字节就能计算出前面一个字节的长度,然后自己往前减就能往前遍历,往后加本身长度就能往后遍历。所以他的查询方式其实和链表是差不多的,只不过更加节省内存而已。

5、SkipList

跳表,首先是链表,元素按照升序排列存储,节点可以包含多个指针,指针的跨度不同。他的zskiplist类有个头尾指针属性,然后节点数量属性,还有个索引层级属性,默认是1。node节点有存的值属性,节点分数排序用,下一个节点指针和索引的跨度,多级指针数组,因为上面的指针数量不确定所以用数组

二、Redis数据结构原理

1、string

基本都是采用raw编码基于sds实现,存储上限是512mb,他有个属性ptr指向了一个sds对象。

当sds小于44字节就会采用embster编码,直接没用指针连着,他直接是连续的一段连续空间。

2、set

Set是采用的dit字典结构哈希表,他只需要key所以value统一为null,当存储的数据都是整数的时候,而且不超过阈值自己配的,就采用inset编码。

3、zset

Zset必须满足键值存储、键必须唯一、可排序。

Skiplist:可以排序,并且同存sorce和ele

Dict:可以键值存储,并且可以根据key找value,但是不能排序。

所以zset的结构体里面直接有两个属性,一个是dict字典,一个是zskiplist跳表。他用了两种结构,性能非常好,但是内存占用太高了。所以当元素数量不多的时候,遍历的方式查询也不会很费时间,元素小于128的时候就用ziplist压缩链表,元素大小小于64的时候采用。如果先进来是用压缩链表,如果超过了大小就转化为字典加跳表,如果已经是了就不需要每次加进来就判断了。

4、Hash

他的底层其实跟zset说差不多的,但是他不需要排序,所以直接干掉跳表,单用哈希表dict就能实现。也是一样数据量小的时候用压缩链表节省内存,当超过设置的阈值就转化为哈希表。

你可能感兴趣的:(Redis,redis,数据结构,数据库,nosql,链表)