redis基础——数据结构

  1. 简单动态字符串(SDS)

在redis中,包含字符串值的键值对都是由SDS实现的

值得注意的是,redis中的键值对的键都是一个字符串对象

 SDS定义:

SDS遵循c字符串以空字符结尾的规则,这样做的好处就是可以利用一部分C语言的库函数

 SDS与C字符串的区别:

  1. SDS字符串以常数级别复杂度获取字符串长度(长度保存在属性len中),而C字符串获取长度需要O(n)复杂度
  2. SDS杜绝缓冲区溢出,C因为不记录自身长度,所以有缓冲区溢出的风险;C在连接字符串时就直接加到后边,而SDS首先会检查空间是否满足要求,若不满足会自动扩展至修改所需大小
  3. SDS减少了修改字符串时带来的内存重分配次数

为了避免运行速度和性能问题,SDS实现了空间预分配惰性空间释放两种优化措施

  1. 二进制安全  C字符串的中间不能包含空字符,否则会被认为是字符串的结束,这就使得C字符串不能保存图片音频视频这样的二级制数据,而SDS字符串使用len属性来判断是否结束,并不是用空字符判断
  2. 兼容部分C字符串函数

  1. 字典

一个键(key)和一个值(value)关联,字典中的每个键都是独一无二的,这数据结构也是redis中应用最广泛的,除了用来表示数据库之外,还用来实现哈希键

 字典的实现:

用哈希表作为底层实现,一个哈希表里有多个哈希节点,每个哈希节点就保存一个键值对

字典:

Redis使用MurmurHash2算法作为计算哈希键的算法

Redis使用链地址法解决哈希冲突问题

哈希表的扩展与收缩:

当哈希表的负载因子小于0.1时,自动开始收缩

 渐进式rehash:

Rehash需要数组迁移,当数据量小的时候还好说,但数据量大的时候,明显达不到性能要求,所以服务器会分多次,渐渐的将数组的迁移工作完成。

渐进式rehash期间的哈希表操作会同时使用两个哈希表ht【0】和ht【1】,找键时会在两个里边都找,而添加操作只针对ht【1】,这一操作保证ht【0】里的键会越来越少

  1. 跳跃表

跳跃表的实现:

跳跃表节点:

  1. 层  level数组包含多个元素,每个元素都有一个指向其他节点的指针
  2. 前进指针  每一层都有一个指向表尾方向的指针(level【i】.forward),用于从表头向表尾方向访问节点
  1. 跨度  层的跨度(level【i】.span属性)用于记录两个节点之间的距离

两个节点之间的跨度越大,他们离得越远

指向Null的所有前进指针跨度都为0,不连接任何节点

  1. 后退指针 用于从表尾指向表头,但不同于前进指针的是,一次只能后退至前一个节点
  2. 分值和成员  分值(score)是一个double类型的浮点数,跳表中的节点都按分值从小到大来排序  成员对象(obj)是一个指针,指向一个字符串对象(保存着SDS值)

跳跃表:

通过一个zskiplist结构来持有跳跃表节点,方便处理

  1. 整数集合

 整数集合的实现:

Contents是底层实现,每个元素都是contents数组的一个项,且按从小到大有序排列,无重复。

Length记录整数集合包含的元素数量(长度)

Encoding决定了数组存放的是哪个类型的整数(8 16 32)

升级操作:

 升级的几个好处:

提升灵活性:可以随意添加数据,不必担心出现类型错误

节约内存:可以确保集合能同时保存三种不同类型,且升级操作只在必要时出现

整数集合不支持降级操作

  1. 压缩列表

压缩列表的构成

压缩列表节点的构成:

 Previous-entry-length

以字节为单位,记录压缩列表前一个节点的长度

 Encoding 

记录了节点的content所保存的数据类型以及长度:一字节两字节或五字节长,值的最高位为00、01、10的是字节数组编码;一字节长,值的最高位以11开头的是整数编码

Content

保存节点的值,节点值可以是一个字节数组或者整数

连锁更新:

描述的是多个节点长度都在254附近,此时一个大于254的节点加入进来,那么前面所说的Previous-entry-length就会从一字节变为五字节,跟多米诺骨牌一样导致全体节点都需要扩容升级,删除节点同样也会导致此操作。

  但这种场景出现的几率不高

  1. 对象

Redis主要根据前面的几种数据结构构成一个对象系统,包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象五种。

对象的类型与编码:

 当我们在数据库中创建对象时,至少会创建两个对象,一个是键一个是值

 Type类型记录了对象的类型(那五个之一),对redis来说,键总是一个字符串对象。

 用type命令时,返回的是值对象的类型,不是键对象的

 对象的ptr指针指向底层实现的数据结构,这些数据结构由对象的encoding属性决定:

每种类型的对象都使用了至少两种不同的编码,这一举措提高了灵活性:

 字符串对象:

 编码的转换:

Int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下会被转换成raw编码的字符串对象。

 对于int字符串来说,比如我们执行一个append操作,由于这个操作只能对字符串执行,此时就会将保存的整数转换为字符串

 Embstr是只读的,也就是说我们对他操作一定会变成raw的

 列表对象:

列表对象的编码可以是ziplist或linkedlist

Ziplist编码的列表对象使用的是压缩列表

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值