Redis面试,你能说清 Redis的数据类型与内部结构吗?

2022-05-25 10:01:54 浏览数 (1)

Redis 面试的时候,有两个高频问题很多面试者往往因为混淆概念而回答错误。

它们就是:Redis 的数据类型,以及 Redis 存储数据的结构。

这里的两道题,问的其实是两个不同的知识点:

· Redis 能存储哪些类型的数据?

· Redis 用什么样的数据结构进行存储?

这其实和我们Java是类似的,Java中的ArrayList类,实际上是用数组结构存储的,HashMap类是利用数组 链表 红黑树存储的

对于同一个种数据类型,可能会有不同的内部结构去存储,对于我们面试来说,数据类型 内部结构 这两个概念一定要清晰分辨。

对于这道题,我们要如何回答呢?

一般来说,我们会从介绍存储数据类型,在到内部数据结构,最后是底层实现原理的步骤进行回答。

1. Redis 的数据类型

有五大数据类型:String,List,Hash,Set,Zset。

String

这是最基本的数据类型,大多数我们使用 Redis 都是以 String 类型为主,对数据库一些不常变但又高频访问的数据做缓存,如店铺的基本信息,商品分类等,这些信息很少有变化。我们直接把实体类转成 JSON 格式,丢到 Redis 里面,在使用的时候,通过 key,去 Redis 里面取出来。在数据库有操作更改的时候,会同时刷新缓存数据。

Hash

经典的 key-value 结构,和 Java 中的 HashMap 很是类似。只是在 Redis 中的Hash一直是链表,并不像Java的HashMap那样会转换为红黑树。

我们可以使用 Hash ,记录商品和对应的详情,或者是对应用户的一些行为。

List

Redis 中的 List 相当于 Java 中 LinkedList,也就是链表(注意:不是数组!),而且这个 List 还可以当队列和栈使用。在产品列表中,我们可以使用 List,接收数据库的数据并且进行展示。

Set

和 Java 中的 HashSet 类似,Set 中的数据是无序且唯一的,适合做去重使用。

ZSet ZSet 在 Set 的基础之上,给每个 value 添加了 score 权重,拥有排序的功能。实际的应用上,在首页的商品推荐中,我使用 Zset,来给每个商品多个维度评分,并记录成 score,然后以此来做各种排行榜。

2. Redis 的数据结构

String

对应着 Redis 内部的 SDS (Simple Dynamic String)

len: 表示buf已经占用的字节数(字符串长度),解决了二进制安全问题

alloc: 表示buf分配的总数量,和len相减就是free的字节数,防止缓冲区溢出,优化的内存惰性释放分配

flags: 表示SDS类型,针对不同的String长度,定制了不同的SDS结构

buf: 真正存储字符串数据的空间,是一个char[]数组

不超过44字节的情况下以embstr存储,超过44字节则以raw形式存储,需要分配两次内存空间(分别为 Redis Object 和 SDS 分配空间)。

List

Redis 在3.2之前采用的是 ZipList 压缩列表和 LinkedList双向链表,并且在 3.2 之后引入了 QuickList。

在数据少的时候Redis采用ZipList来存储,可以有效的节省内存空间。但是在修改元素时, 为保证 ZipList 内存空间的连续性,需要重新分配内存存储空间,会造成一定的性能影响,所以在数据多的时候 Redis 采用 LinkedList(双向链表结构),而在Redis 3.2之后,为了综合考虑时间效率与空间效率引入了QuickList。

QuickList 实际上是 ZipList和 LinkedList的混合体。

它将 LinkedList按段切分,每一段使用 ZipList 来紧凑存储,多个 ZipList 之间使用双向指针串接起来。在 QuickList 内部,为进一步节约空间,还会使用LZF算法对 ZipList 进行压缩存储。

Hash

哈希类型的内部结构有两种:ZipList压缩列表,HashTable哈希表。只有当存储的数据量比较小的情况下,Redis 才使用 ZipList 压缩列表来实现,其他情况则是对应着 Dict。

Dict 的实现是有两个 HashTable, 一般来说,只有一个有值;还有一个在扩容的时候需要。

Set

当数据量少,数据比较小的时候采用ZipList ,否则采用 Dict。

但是对于 Set 来说,该 HashTable 的value值为NULL,通过key来存储元素。

ZSet

和Set 类似数据少的时候采用ZipList ,否则采用 Dict zSkipList 同时进行存储,既能高效的范围查询也能兼顾高效单点查询。

• Dict,字典类型, 其中key表示zset的成员数据,value表示zset的分值。• zSkipList,跳跃表,按分值排序存储成员数据。

• zSkipList 每个元素Node中*obj和Dic中*key指向同一个具体元素,所以不会存在多余的内存消耗问题。

zSkipList

跳表是用来替代平衡树的数据结构,由二叉树回归链表,提高数据的插入效率(简化树的自平衡过程),同时因为查找过程的跳跃性,比线性查找省时。当数据量越来越大时,这种结构的优势就更加明显了。

所以,面试官问我们 Redis 的可存储数据类型以及 Redis 的内部结构时,根本上考查的是我们对于 Redis 知识点的理解和应用,我们学习 Redis,不仅仅是死记硬背面试题,更重要的是实践:如,Redis 排行榜怎么实现,布隆过滤器怎么去做,分布式锁实现,限流等等……

这些都是需要多思考的点,你学会了吗?

0 人点赞