redis底层—数据结构

0.redisObject

每一种redis数据类型(字符串、list、set、zset、hash)对应一个redisObject

redis中不同数据类型对应的编码底层:

 

1.字符串底层:动态字符串sds

redis没有直接使用c语言的字符串,是因为c语言的字符串存在一些问题:

1.获取字符串长度的需要通过运算
2.非二进制安全
3.不可修改

故redis自己实现了一种字符串,叫sds(动态字符串) 。

优点:

1.获取字符串长度的时间复杂度为0(1)
2.支持动态扩容
3.减少内存分配次数
4.二进制安全 

2.List底层:quicklist(双端链表,linkedlist+ziplist)

由于List的特点需要从两端对元素进行操作,所以考虑linkedlist。而linkedlist是通过指针进行数据连接,指针是8字节无符号整数,故linkedlist占用内存较大,在数据量不大的情况下采用ziplist实现。在redis3.2之前,List底层都是采用linkedlist和ziplist结合的方式,而在3.2版本之后,List底层采用quicklist实现。它结合了二者的优点,是实现List的最佳方案。

ziplist特点:

quicklist特点:

quicklist如何解决ziplist的问题?

 3.Set底层:intset或dict

set数据类型对查询的效率要求非常高,考虑到这一点使用dict(ht)来实现set无疑是最合适的,而dict数据结构在元素数量较少的情况下又有着内存占用过大的问题,所以在少量元素的情况下,且存储的数据都为int,set会使用intset数据结构来实现。

intset特点:

1.Redis会确保Intset中的元素唯一、有序
2.具备类型升级机制,可以节省内存空间
4.底层采用二分查找方式来查询

dict(ht)特点:

 缺点:内存不连续,会导致内存碎片,不利于内存最大化使用

4.ZSet底层:skiplist+dict,或ziplist

zset底层使用调表和dict(ht)来实现,这种方式的优势是性能非常强大,键唯一、可排序、支持键值对查找等,但是缺点也很明显,由于使用两种数据结构使得这种数据类型非常占用内存空间,在元素数量不多时,zset会采用ziplist来实现。

skiplist特点:

1.跳跃表是一个双向链表,每个节点都包含score和ele值
2.节点按照score值排序,score值一样则按照ele字典排序
3.每个节点都可以包含多层指针,层数是1到32之间的随机数
4.不同层指针到下一个节点的跨度不同,层级越高,跨度越大
5.增删改查效率与红黑树基本一致,实现却更简单 

 5.Hash底层:dict或ziplist

hash和zset的结构很类似,都需要键值对查找、键唯一,但hash是无序的,故不需要跳表来实现排序。故在数据量小时使用ziplist,数据量大时使用dict

6.几个问题

1.为什么说ziplist只能在低数据量情况下使用?

ziplist使用伪双向链表的数据结构存储,但它并不是传统意义上的链表,原因是它的节点不使用指针,但是通过连续的内存片记录数据,在访问元素时,通过每个节点记录的字节数来计算下一个节点的内存位置。这种方式的好处是ziplist的内存占用相当低(因为指针占用8字节,从某种意义上来说无故消耗了8字节空间),坏处是扩容的代价较大,一个原因是一片连续的内存空间很难申请,另一个原因是当某个节点的内存占用较大时会影响其他节点的记录字节,产生平白无故的内存消耗。

2.跳表和传统链表有什么区别?

首先跳表的元素是按score的值排列存储的,其次它的每个结构可能包含多个指针,每个指针的跨度不同,从而使跳表能跨多个元素访问,提升了访问速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deryck_德瑞克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值