本文参考 嗨客网 Redis面试题

Redis底层数据结构

Redis 的五大数据类型也称五大数据对象,即分别为 stringlisthashsetzset,但 Redis 并没有直接使用这些结构来实现键值对数据库,而是使用这些结构构建了一个对象系统 redisObject。

这个对象系统包含了五大数据对象,字符串对象(string)、列表对象(list)、哈希对象(hash)、集合(set)对象和有序集合对象(zset);而这五大对象的底层数据编码可以用命令 OBJECT ENCODING 来进行查看。

Redis对象

Redis 基于上述的数据结构自定义一个 Object 系统,Object 结构,即 redisObject 结构:

typedef struct redisObject{//类型unsigned type:4;//编码unsigned encoding:4;//指向底层实现数据结构的指针void *ptr;…..
}

Object 系统包含五种 Object:

  • String:字符串对象
  • List:列表对象
  • Hash:哈希对象
  • Set:集合对象
  • ZSet:有序集合

Redis 使用对象来表示数据库中的键和值,即每新建一个键值对,至少创建有两个对象,而且使用对象的具有以下好处:

  1. redis 可以在执行命令前会根据对象的类型判断一个对象是否可以执行给定的命令。
  2. 针对不同的使用场景,为对象设置不同的数据结构实现,从而优化对象的不同场景夏的使用效率。
  3. 对象系统还可以基于引用计数计数的内存回收机制,自动释放对象所占用的内存,或者还可以让多个数据库键共享同一个对象来节约内存。
  4. redis 对象带有访问时间记录信息,使用该信息可以进行优化空转时长较大的 key,进行删除!

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

编码常量 编码对应的底层数据结构
REDIS_ENCODING_INT long 类型的整数
REDIS_ENCODING_EMBSTR embstr 编码的简单动态字符串
REDIS_ENCODING_RAW 简单动态字符串
REDIS_ENCODING_HT 字典
REDIS_ENCODING_LINKEDLIST 双向链表
REDIS_ENCODING_ZIPLIST 压缩列表
REDIS_ENCODING_INTSET 整数集合
REDIS_ENCODING_SKIPLIST 跳跃表和字典

每种 Object 对象至少有两种不同的编码,对应关系:

类型 编码 对象
String int 整数值实现
String embstr sds实现 <=39 字节
String raw sds实现 > 39字节
List ziplist 压缩列表实现
List linkedlist 双端链表实现
Set intset 整数集合使用
Set hashtable 字典实现
Hash ziplist 压缩列表实现
Hash hashtable 字典使用
Sorted set ziplist 压缩列表实现
Sorted set skiplist 跳跃表和字典

String对象实现

说明

字符串对象底层数据结构实现为简单动态字符串(SDS)和直接存储,但其编码方式可以是 int、raw 或者 embstr,区别在于内存结构的不同。

结构

int编码

字符串保存的是整数值,并且这个正式可以用 long 类型来表示,那么其就会直接保存在 redisObject 的 ptr 属性里,并将编码设置为 int,如图:

raw编码

字符串保存的大于 32 字节的字符串值,则使用简单动态字符串(SDS)结构,并将编码设置为 raw,此时内存结构与 SDS 结构一致,内存分配次数为两次,创建 redisObject 对象和 sdshdr 结构,如图:

embstr编码

字符串保存的小于等于 32 字节的字符串值,使用的也是简单的动态字符串(SDS 结构),但是内存结构做了优化,用于保存顿消的字符串;内存分配也只需要一次就可完成,分配一块连续的空间即可,如图:

String对象之间的编码转换

int 编码的字符串对象和 embstr 编码的字符串对象在条件满足的情况下,会被转换为 raw 编码的字符串对象。比如:对 int 编码的字符串对象进行 append 命令时,就会使得原来是 int 变为 raw 编码字符串。

C字符串与SDS

C 字符串 SDS
获取字符串长度的复杂度为 O(N) 获取字符串长度的复杂度为 O(1)
API 是不安全的,可能会造成缓冲区溢出 API 是安全的,不会造成缓冲区溢出
修改字符串长度 N 次必然需要执行 N 次内存重分配 修改字符串长度 N 次最多执行 N 次内存重分配
只能保存文本数据 可以保存二进制数据和文本文数据
可以使用所有 <String.h> 库中的函数 可以使用一部分 <string.h> 库中的函数

总结

  1. 在 Redis 中,存储 long、double 类型的浮点数是先转换为字符串再进行存储的。
  2. raw 与 embstr 编码效果是相同的,不同在于内存分配与释放,raw 两次,embstr 一次。
  3. embstr 内存块连续,能更好的利用缓存在来的优势。
  4. int 编码和 embstr 编码如果做追加字符串等操作,满足条件下会被转换为 raw 编码;embstr 编码的对象是只读的,一旦修改会先转码到 raw。

List对象

说明

list 对象可以为 ziplist 或者为 linkedlist,对应底层实现 ziplist 为压缩列表,linkedlist 为双向列表。

结构

比如如下结构:

Redis> RPUSH numbers "CcWw" 520 1

用 ziplist 编码的 List 对象结构:

用 linkedlist 编码的 List 对象结构:

压缩表结构

压缩表各部分组成说明如下:

zlbytes:记录整个压缩列表占用的内存字节数,在压缩列表内存重分配,或者计算 zlend 的位置时使用。

zltail:记录压缩列表表尾节点距离压缩列表的起始地址有多少字节,通过该偏移量,可以不用遍历整个压缩列表就可以确定表尾节点的地址。

zllen:记录压缩列表包含的节点数量,但该属性值小于 UINT16_MAX(65535)时,该值就是压缩列表的节点数量,否则需要遍历整个压缩列表才能计算出真实的节点数量。

entryX:压缩列表的节点。

zlend:特殊值 0xFF(十进制 255),用于标记压缩列表的末端。

List对象的编码转换

当 list 对象可以同时满足以下两个条件时,list 对象使用的是 ziplist 编码:

  1. list 对象保存的所有字符串元素的长度都小于 64 字节。
  2. list 对象保存的元素数量小于 512 个。

不能满足这两个条件的 list 对象需要使用 linkedlist 编码。

Hash对象

说明

Hash 对象的编码可以是 ziplist 或者 hashtable,其中,ziplist 底层使用压缩列表实现:

  1. 保存同一键值对的两个节点紧靠相邻,键 key 在前,值 vaule 在后。
  2. 先保存的键值对在压缩列表的表头方向,后来在表尾方向。

hashtable 底层使用字典实现,Hash 对象种的每个键值对都使用一个字典键值对保存:

  1. 字典的键为字符串对象,保存键 key。
  2. 字典的值也为字符串对象,保存键值对的值。

结构

比如 HSET 命令:

redis>HSET author name  "Ccww"
(integer)redis>HSET author age  18
(integer)redis>HSET author sex  "male"
(integer)

ziplist 的底层结构:

hashtable 底层结构:

Hash对象的编码转换

当 list 对象可以同时满足以下两个条件时,list 对象使用的是 ziplist 编码:

  1. list 对象保存的所有字符串元素的长度都小于 64 字节。
  2. list 对象保存的元素数量小于 512 个。

不能满足这两个条件的 hash 对象需要使用 hashtable 编码,但这两个条件的上限值是可以修改的,可查看配置文件 hash-max-zaiplist-value 和 hash-max-ziplist-entries。

Set对象

说明

Set 对象的编码可以为 intset 或者 hashtable:

  1. intset 编码:使用整数集合作为底层实现,set 对象包含的所有元素都被保存在 intset 整数集合里面。
  2. hashtable 编码:使用字典作为底层实现,字典键 key 包含一个 set 元素,而字典的值则都为 null。

结构

inset 编码 Set 对象结构:

redis> SAD number  1 3 5

hashtable 编码 Set 对象结构:

redis> SAD Dfruits  “apple”  "banana" " cherry"

Set对象的编码转换

使用 intset 编码:

  1. set 对象保存的所有元素都是整数值。
  2. set 对象保存的元素数量不超过 512 个。

不能满足这两个条件的 Set 对象使用 hashtable 编码。

ZSet对象

说明

ZSet 对象的编码可以为 ziplist 或者 skiplist,ziplist 编码,每个集合元素使用相邻的两个压缩列表节点保存,一个保存元素成员,一个保存元素的分值,然后根据分数进行从小到大排序。

结构

ziplist 编码的 ZSet 对象结构:

Redis>ZADD price 8.5 apple 5.0 banana 6.0 cherry

skiplist 编码的 ZSet 对象使用了 zset 结构,包含一个字典和一个跳跃表:

Type struct zset{Zskiplist *zsl;dict *dict;...
}

ZSet对象的编码转换

当 ZSet 对象同时满足以下两个条件时,对象使用 ziplist 编码:

  1. 有序集合保存的元素数量小于 128 个。
  2. 有序集合保存的所有元素的长度都小于 64 字节。

不能满足以上两个条件的有序集合对象将使用 skiplist 编码,同时,可以通过配置文件中 zset-max-ziplist-entries 和 zset-max-ziplist-vaule 来改变这个数值。

Redis底层数据结构总结

Redis 的 redisObject 结构如下图:

五大数据类型对应的底层数据结构如下图所示:

更多

原文链接链接

其他目录

更多文章,可以关注下方公众号:

Redis面试题-Redis底层数据结构相关推荐

  1. 【重难点】【Redis 01】为什么使用 Redis、Redis 的线程模型、Redis 的数据类型及其底层数据结构

    [重难点][Redis 01]为什么使用 Redis.Redis 的线程模型.Redis 的数据类型及其底层数据结构 文章目录 [重难点][Redis 01]为什么使用 Redis.Redis 的线程 ...

  2. 三、redis原理之list底层数据结构

    一.redis原理之list底层数据结构ziplist和quicklist. 快速列表 quicklist[quicklist = 链表+ziplist] 首先在列表元素较少的情况下会使用一块连续的内 ...

  3. 四、redis原理之set底层数据结构

    一.redis原理之set底层数据结构? 其底层有两种实现方式: 1.当value是整数值时,且数据量不大时使用inset来存储, 2.其他情况都是用字典dict来存储 inset的结构: typed ...

  4. Redis面试题-Redis跳跃表

    本文参考 嗨客网 Redis面试题 Redis跳跃表 什么是跳跃表 Redis 中的跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的. 为什么使用跳 ...

  5. Redis面试题-Redis哨兵模式

    本文参考 嗨客网 Redis面试题 Redis哨兵模式 什么是Redis哨兵模式 Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress ...

  6. Redis面试题-Redis集群Twemproxy与Codis

    本文参考 嗨客网 Redis面试题 Redis集群Twemproxy与Codis Redis常见集群技术 长期以来,Redis 本身仅支持单实例,内存一般最多 10~20GB.这无法支撑大型线上业务系 ...

  7. Redis中ZSet的底层数据结构跳跃表skiplist,你真的了解吗?

    欢迎大家关注我的微信公众号[老周聊架构],Java后端主流技术栈的原理.源码分析.架构以及各种互联网高并发.高性能.高可用的解决方案. 一.前言 老周写这篇文章的初衷是这样的,之前项目中有大量使用 R ...

  8. 一、redis原理之string底层数据结构SDS

    一.前言 我们说Redis 是用 C 语言写的,,但是对于Redis的字符串,却不是 C 语言中的字符串(即以空字符'\0'结尾的字符数组),它是自定义的数据结构SDS(simple dynamic ...

  9. php redis面试题,Redis面试常见问题

    Redis 单线程为什么还能这么快? 完全基于内存,绝大部分请求是纯粹的内存操作. 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的. 采用单线程,避免了不必要的上下文切换和竞争 ...

最新文章

  1. 第三周实践项目8 以第一个元素为分界线,将所有小于它的元素移到该元素的前面,将所有大于它的元素移到该元素的后面。
  2. shujufenxi : shenzhenditie
  3. Android样式和主题(二):系统有哪些主题
  4. 出现opencv error: assertion failed..........错误时, 一步解决
  5. java生日正则表达式_Java编程基础15——正则表达式常用工具类
  6. php 生产环境配置,生产环境php.ini配置文件修改
  7. 利用python编写祝福_手把手|教你用Python换个姿势,送狗年祝福语
  8. ECharts学习--雷达图
  9. (二)智能化技术如何赋能能源数字化转型及智慧化应用?
  10. 上研动力小课堂丨柴油机启动困难原因大揭秘(上篇)
  11. 人工神经网络理论及应用pdf,人工智能的相关书籍
  12. java eclipse怎么下载_javaeclipse简介(附下载地址和安装包)
  13. Win10新加内存条后可用内存没增加解决方案
  14. 本地JSON格式化工具下载
  15. 否定、合取、析取、条件、双条件(同或)、异或、条件否定、与非、或非
  16. 传统医学到现代医学的研究技能演变(逻辑推理和实验的意义)【科学研究的步骤】
  17. 【STC单片机学习】高级外设和项目篇二:红外遥控
  18. 2023年清华大学-中国人民银行金融研究所联合培养项目招收公开招考博士研究生拟录取名单公示
  19. 前后端分离实现在线记账功能,前端使用vue,后端使用springmvc
  20. 使用CANdb++制作dbc文件(小白笔记)

热门文章

  1. 3d游戏场景建模设计师需要学哪些软件?
  2. 计算机图形学的进展与展望
  3. 便利蜂是“冬眠”还是“假寐”,只有时间知道
  4. 模型可解释性-SHAPE
  5. 用sklearn.preprocessing做数据预处理(四)——OneHotEncoder
  6. java workflow jbpm_工作流(workflow)定义和jBPM
  7. 等概率整群抽样与多阶段抽样
  8. ubuntu 下实现 quagga镜像
  9. 中国少儿模特明星盛典 《荣耀王者》主题曲 即将全网发布
  10. 计算机视觉中的多视图几何 -- 2D射影几何与变换 --无穷远直线、虚圆点及其对偶以及恢复图像的仿射性质