面试:原来Redis常用的五种数据类型底层结构是这样的

本文涉及的产品
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
简介: 在Redis中会涉及很多数据结构,比如SDS,双向链表、字典、压缩列表、整数集合等等。Redis会基于这些数据结构自定义一个对象系统,而且自定义的对象系统有很多好处

在Redis中会涉及很多数据结构,比如SDS,双向链表、字典、压缩列表、整数集合等等。Redis会基于这些数据结构自定义一个对象系统,而且自定义的对象系统有很多好处。


通过对以下的Redis对象系统的学习,可以了解Redis设计原理以及初衷,为了我们在使用Redis的时候,更加能够理解到其原理和定位问题。


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 对象


字符串对象编码可以int 、raw或者embstr,如果保存的值为整数值且这个值可以用long类型表示,使用int编码,其他编码类似。


比如:int编码的String Object


redis> set number 520 
 ok
 redis> OBJECT ENCODING number 
"int"
复制代码


String Object结构:


4.png


String 对象之间的编码转换


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


比如:对int编码的字符串对象进行append命令时,就会使得原来是int变为raw编码字符串


## List对象


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


Redis>RPUSH numbers “Ccww” 520 1
复制代码


用ziplist编码的List对象结构:


5.png


用linkedlist编码的List对象结构:


6.png


List对象的编码转换:


当list对象可以同时满足以下两个条件时,list对象使用的是ziplist编码: 1. list对象保存的所有字符串元素的长度都小于64字节 2. list对象保存的元素数量小于512个, 不能满足这两个条件的list对象需要使用linkedlist编码。


Hash对象


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


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


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


  • 字典的键为字符串对象,保存键key
  • 字典的值也为字符串对象,保存键值对的值


比如:HSET命令


redis>HSET author name  "Ccww"
(integer)
redis>HSET author age  18
(integer)
redis>HSET author sex  "male"
(integer)
复制代码


ziplist的底层结构:


7.png


hashtable底层结构:


8.png


Hash对象的编码转换:


当list对象可以同时满足以下两个条件时,list对象使用的是ziplist编码: 1. list对象保存的所有字符串元素的长度都小于64字节 2. list对象保存的元素数量小于512个, 不能满足这两个条件的hash对象需要使用hashtable编码


Note:这两个条件的上限值是可以修改的,可查看配置文件hash-max-zaiplist-value和hash-max-ziplist-entries


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

inset编码Set对象结构:


redis> SAD number  1 3 5 
复制代码


9.png


hashtable编码Set对象结构:


redis> SAD Dfruits  “apple”  "banana" " cherry"
复制代码


10.png


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
复制代码


11.png


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


Type struct zset{
  Zskiplist *zsl;
  dict *dict;
  ...
}
skiplist编码的ZSet对象结构
复制代码


12.png


ZSet对象的编码转换


当ZSet对象同时满足以下两个条件时,对象使用ziplist编码 1. 有序集合保存的元素数量小于128个 2. 有序集合保存的所有元素的长度都小于64字节 不能满足以上两个条件的有序集合对象将使用skiplist编码。


Note: 可以通过配置文件中zset-max-ziplist-entries和zset-max-ziplist-vaule


各位看官还可以吗?喜欢的话,动动手指点个💗,点个关注呗!!谢谢支持!



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
Java
【Java基础面试四】、介绍一下Java的数据类型
这篇文章介绍了Java的数据类型,包括8种基本数据类型(整数、浮点、字符、布尔)和3类引用数据类型(数组、类、接口),并提供了基本数据类型所占内存空间和数据范围的详细信息。
|
6天前
|
存储 缓存 NoSQL
【Java面试题汇总】Redis篇(2023版)
Redis的数据类型、zset底层实现、持久化策略、分布式锁、缓存穿透、击穿、雪崩的区别、双写一致性、主从同步机制、单线程架构、高可用、缓存淘汰策略、Redis事务是否满足ACID、如何排查Redis中的慢查询
【Java面试题汇总】Redis篇(2023版)
|
1月前
|
NoSQL 安全 Java
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
这篇文章深入探讨了Redis中的String数据类型,包括键操作的命令、String类型的命令使用,以及String在Redis中的内部数据结构实现。
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
|
1月前
|
NoSQL Java Redis
Redis5种数据类型
这篇文章介绍了Redis的五种数据类型:字符串、列表、集合、有序集合和哈希,并通过代码示例展示了如何在Spring框架中使用RedisTemplate操作这些数据类型。
Redis5种数据类型
|
1月前
|
存储 NoSQL 算法
Redis6入门到实战------ 三、常用五大数据类型(列表(List)、集合(Set)、哈希(Hash)、Zset(sorted set))
这是关于Redis 6入门到实战的文章,具体内容涉及Redis的五大数据类型:列表(List)、集合(Set)、哈希(Hash)、有序集合(Zset(sorted set))。文章详细介绍了这些数据类型的特点、常用命令以及它们背后的数据结构。如果您有任何关于Redis的具体问题或需要进一步的帮助,请随时告诉我。
|
1月前
|
存储 Java
【Java集合类面试二十九】、说一说HashSet的底层结构
HashSet的底层结构是基于HashMap实现的,使用一个初始容量为16和负载因子为0.75的HashMap,其中HashSet元素作为HashMap的key,而value是一个静态的PRESENT对象。
|
29天前
|
消息中间件 存储 NoSQL
redis实战——go-redis的使用与redis基础数据类型的使用场景(一)
本文档介绍了如何使用 Go 语言中的 `go-redis` 库操作 Redis 数据库
redis实战——go-redis的使用与redis基础数据类型的使用场景(一)
|
30天前
|
缓存 NoSQL Redis
redis常见面试题总结(上)
Redis 提升读写性能,减少 MySQL 请求。优点包括:内存存储加速数据获取,支持多样数据结构如哈希和有序集合,事务确保操作原子性,具备队列、主从复制及持久化功能。相较于 Memcache,Redis 数据类型更丰富,支持数据持久化与恢复,单值大小可达 512MB。其单线程设计基于 C 语言实现,使用非阻塞 IO 复用来高效处理请求。主从同步机制确保数据一致性,首次同步需生成 RDB 文件。事务虽保证命令序列化执行但不支持回滚。Bigkey 会增加网络负载并可能导致内存不平衡。缓存雪崩、穿透等问题可通过分散过期时间和布隆过滤器解决。缓存预热则预先填充热点数据。
21 0
|
1月前
|
存储 缓存 NoSQL
Redis深度解析:部署模式、数据类型、存储模型与实战问题解决
Redis深度解析:部署模式、数据类型、存储模型与实战问题解决
|
1月前
|
NoSQL Java Redis
Redis字符串数据类型之INCR命令,通常用于统计网站访问量,文章访问量,实现分布式锁
这篇文章详细解释了Redis的INCR命令,它用于将键的值增加1,通常用于统计网站访问量、文章访问量,以及实现分布式锁,同时提供了Java代码示例和分布式锁的实现思路。
38 0