redis设计与实现(一):数据结构与对象

17 篇文章 0 订阅
11 篇文章 0 订阅

该博客是读《redis设计与实现》后的内容笔记整理

数据结构与对象

一、简单动态字符串:SDS

Redis使用C字符串作为字面量,但大多数情况下,使用SDS(Simple Dynamic String)作为字符串表示。

1. SDS是Redis的默认字符串存储类型,是一种抽象类型

2. 有以下优点:

  • 常数复杂度获取字符串长度(获取字符串长度的复杂度为0(1)
  • 杜绝缓冲区溢出(API是安全的,不会造成缓冲区溢出
  • 减少修改字符串长度时所需的内存重分配次数(修改字符串长度N次最多需要执行N次内存重分配
  • 二进制安全(可以保存文本或者二进制数据
  • 兼容部分C字符串函数(可以使用部分<string.h>库中的函数

3.SDS的主要操作API:

在这里插入图片描述

二、链表

1. 链表的应用:列表键、发布与订阅、慢查询、监视器等

2. Redis的链表实现:

  • 双端链表
  • 每个链表节点由一个listNode结构表示,每个节点都有一个只想前置节点和后置节点的指针
  • 是无环链表,因为链表表头节点的前置节点和表尾的后置节点都指向NULL
  • Redis通过为链表设置不同的类型特定函数,来保存各种不同类型的值

3. 操作链表和链表节点的API

在这里插入图片描述

三、字典

1. Redis中的字典使用哈希表作为底层实现

  • 每个字典有两个哈希表,一个平时使用,另一个尽在rehash时使用

2. 当字典被用作数据库的底层实现或哈希键的底层实现时,Redis用MurmurHash2算法来计算键的哈希值

3. 在对哈希表使用链地址法来解决键冲突,被分配到同一个索引上的多个键值对会连接成一个单向列表

在对哈希表进行扩展或收缩时,程序需要将现有哈希表包含的所有键值对rehash到哈希表里

  • rehash过程并不是一次性完成,而是渐进式地完成

4.字典的主要操作API

在这里插入图片描述

五、跳跃表

1. 跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。

2. Redis使用跳跃表作为有序集合键的底层实现之一

  • 如果一个有序集合包含的元素数量比较多
  • 又或者有序集合中元素的成员是比较长的字符串
  • Redis就会使用跳跃表作为有序集合键的底层实现

3. 跳跃表实现由zskiplist和zskiplistNode两个结构组成

  • zskiplist用于保存跳跃表信息,比如表头节点、表尾节点、长度
  • zskiplistNode则用于表示跳跃表的节点

4. 每个跳跃表节点的层高都是1至32之间的随机数

5. 在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的

6. 跳跃表的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序

7. 跳跃表API

在这里插入图片描述

六、整数集合

  • 是集合键的底层实现之一
  • 当一个集合只包含整数值元素,并且这个集合的元素数量不多时,就会使用整数集合作为集合键的底层实现
  • 可保存类型:int16_t、int32_t、int64_t的整数值,并且保证集合中不会出现重复元素

1. 整数集合的底层实现为数组

  • 这个数组以有序、无重复的方式保存集合元素
  • 在有需要时, 程序会根据新添加元素的类型,改变这个数组的类型

2. 升级操作为整数集合带来了操作上的灵活性,并尽可能的节约了内存

3. 整数集合只支持升级操作,不支持降级操作

4. 整数集合API

在这里插入图片描述

七、压缩列表

  • 是列表键和哈希键的底层实现之一
  • 当一个列表键只包含少量列表项,并且每个列表项是小整数值或长度较短的字符串,Redis就会用压缩列表来做列表键的底层实现

1. 压缩列表是为节约内存而开发的顺序型数据结构

2. 压缩列表可以包含多个节点,每个节点可以保存一个字节数组或整数值

3. 添加新节点到压缩列表,或者从压缩列表删除节点,可能会引发连锁更新操作,但这种操作出现几率不高

4. 压缩列表API

在这里插入图片描述

八、对象

  • 上边介绍了Redis用到的主要数据结构:简单动态字符串(SDS)、双端链表、字典、压缩列表、整数集合等,
    • 但它并没有直接使用这些数据结构来实现键值对数据库
    • 而是基于这些数据结构创建了一个对象系统,
    • 这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象
    • 每种对象都用到了至少一种数据结构

1. 字符串对象

  • 字符串对象的编码:int、raw、embstr

2. 列表对象

  • 列表对象的编码:ziplist、linkedlis

3. 哈希对象

  • 哈希对象的编码:ziplist、hashtable
    • ziplist编码的哈希对象使用压缩列表作为底层实现
      • 每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,
      • 再将保存了值的压缩列表节点推入到压缩列表表尾
      • 因此,保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后;
      • 先添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。
    • hashtable编码的哈希对象使用字典作为底层实现
      • 哈希对象中的每个键值对都使用一个字典键值对来保存
        • 字典的每个键都是一个字符串对象,对象中保存了键值对的键;
        • 字典的每个值都是一个字符串对象,对象中保存了键值对的值

4.集合对象

  • 集合对象的编码:intset、hashtable

5.有序集合对象

  • 有序集合的编码:ziplist、skiplist

6.类型检查与命令多态

  • 可对如何类型的键执行: DEL、EXPIRE、RENAME、TYPE、OBJECT等
  • 只能对特定类型的键执行:
    • 字符串:SET、GET、APPEND、STRLEN…
    • 哈希键:HDEL、HSET、HGET、HLEN…
    • 列表键:RPUSH、LPOP、LINSERT、LLEN…
    • 集合键:SADD、SPOP、SINTER、SCARD…
    • 有序集合键:ZADD、ZCARD、ZRANK、ZSCORE…
1)类型检查通过redisObject结构的type属性实现
  • 在执行一个类型特定命令前,服务器先检查输入数据库键的值对象是否为执行命令多虚的类型,是则对键执行知道的命令
  • 不是,服务器将拒绝执行命令,并向客户端返回类型错误
2)多态命令的实现
  • 根据值对象的编码方式,选择正确的命令实现代码来执行命令

7. 内存回收

  • 因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制
  • 通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

8.对象共享

  • 除了用于实现引用计数内存回收机制之外,对象的引用计数属性还带有对象共享的作用
  • 尽管共享更复杂的对象可以节约更多的内存,但受到CPU时间的限制,Redis只对包含整数值的字符串对象进行共享

9. 对象的空转时长

  • 除了前面介绍过的type、encoding、ptr和refcount四个属性之外,redisObject结构包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间
  • OBJECT IDLETIME命令可以打印出给定键的空转时长,这一空转时长就是通过将当前时间减去键的值对象的lru时间计算得出的

OBJECT IDLETIME命令的实现是特殊的,这个命令在访问键的值对象时,不会修改值对象的lru属性

  • 如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存。

10.重点

  1. Redis数据库中的每个键值对的键和值都是一个对象。
  2. Redis共有字符串、列表、哈希、集合、有序集合五种类型的对象,每种类型的对象至少都有两种或以上的编码方式,不同的编码可以在不同的使用场景上优化对象的使用效率。
  3. 服务器在执行某些命令之前,会先检查给定键的类型能否执行指定的命令,而检查一个键的类型就是检查键的值对象的类型。
  4. Redis的对象系统带有引用计数实现的内存回收机制,当一个对象不再被使用时,该对象所占用的内存就会被自动释放。
  5. Redis会共享值为0到9999的字符串对象。
  6. 对象会记录自己的最后一次被访问的时间,这个时间可以用于计算对象的空转时间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值