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

简介: 在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


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



目录
相关文章
|
8月前
|
存储 缓存 NoSQL
Redis常见面试题全解析
Redis面试高频考点全解析:从过期删除、内存淘汰策略,到缓存雪崩、击穿、穿透及BigKey问题,深入原理与实战解决方案,助你轻松应对技术挑战,提升系统性能与稳定性。(238字)
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
11月前
|
存储 NoSQL 定位技术
Redis数据类型面试给分情况
Redis常见数据类型包括:string、hash、list、set、zset(有序集合)。此外还包含高级结构如bitmap、hyperloglog、geo。不同场景可选用合适类型,如库存用string,对象存hash,列表用list,去重场景用set,排行用zset,签到用bitmap,统计访问量用hyperloglog,地理位置用geo。
558 5
|
11月前
|
NoSQL Java Redis
Redis基本数据类型及Spring Data Redis应用
Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。
799 2
|
12月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
650 6
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
436 4
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
2606 2