今天我才知道Redis有7种数据类型...

原创
存储 存储软件 开发工具 Redis
面试官:Redis 有哪几种数据类型?存储原理是什么?具体适应哪些应用场景?是否历历在目,这是 Redis 关于数据类型的面试 3 连问,是除“Redis 持续化”外的最常见 Redis 考题。

【51CTO.com原创稿件】面试官:Redis 有哪几种数据类型?存储原理是什么?具体适应哪些应用场景?是否历历在目,这是 Redis 关于数据类型的面试 3 连问,是除“Redis 持续化”外的最常见 Redis 考题。

[[387092]] 

图片来自 Pexels

但是,无论面试官的提问、网上的答案,基本都是错的!本文将依据源码向读者做剖析,深入浅出,过目不忘。

查谷歌众说纷纭

说法一:5 种

Redis 支持 5 种数据类型:

  • String(字符串)
  • List(列表)
  • Set(集合)
  • Sorted Set(有序集合)
  • Hash(哈希)

这也是被行业普遍认可,最最常见的答案。至于这 5 种类型的详解,网上已经铺天盖地,这里不打算重复探讨,请读者自行温习。

说法二:6 种 

包含了“说法一”的 5 种,还包含了:HyperLogLog(基数)。

也就是:String(字符串)、List(列表)、Set(集合)、Sorted Set(有序集合)、Hash(哈希)、HyperLogLog(基数)共 6 种。

 

说法三:9 种

包含了“说法二”的 6 种,还包含了:Bitmap(位集合)、Geospatial(地理空间索引)、Streams(流信息)3 种。

也就是:String(字符串)、List(列表)、Set(集合)、Sorted Set(有序集合)、Hash(哈希)、HyperLogLog(基数)、Bitmap(位集合)、Geospatial(地理空间索引)、Streams(流信息)共 9 种。

还有一说,并未包含 Streams(流信息),但是包含了 BloomFilter(布隆过滤器),这个不重要,但都称是 9 种,尚未见有 10 种的说法。

 

从官网找答案

英文官网:https://redis.io/,中文官网:http://www.redis.cn/,首页如下:

请留意这一句: 

Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams.

很明显,官网提到 Redis 支持的数据类型一共有 9 种。跟上文的“说法三”基本一致。

另外值得注意的是,中文官网没有提及 Stream,也就是漏了一句话。因为 Stream 是在 2018 年 10 月 5.0 版本引入,但是中文官网至今没有更新,是个非常明显的文案 Bug(不知道反馈被采纳会不会有奖金)。

那么问题到此解决了?还没有!问题才刚刚开始。

具体问题具体分析

“说法一:5 种” 为什么会被行业普遍认可

先来看看 Redis 的各种高级功能类型被引入的版本,如下表:

 

很明显,原因是:这些功能都是后续版本陆续引入的,5 种数据类型乃最经典的 5 种类型,所以代代相传,传承已久。

再来看看 Redis 的各个大版本的发布时间,如下表:

 

也就是说,“5 种数据类型”的认知,业界持续已有 10 年之久,认知的错误也有 10 年之久。

“说法三:9 种” 是否正确

要回答这个问题,先了解 Redis 的数据类型如何查看,可通过 type KEY_NAME 命令。

另外,通过 object encoding KEY_NAME 命令可查具体的编码结构,这里仅稍作提及,不在本文的讨论范围内。

①String

  1. localhost:6379> set str:hello world 
  2. OK 
  3. localhost:6379> get str:hello 
  4. "world" 
  5. localhost:6379> type str:hello 
  6. string 

②Bitmap

  1. localhost:6379> setbit str:a 1 1 
  2. (integer) 0 
  3. localhost:6379> setbit str:a 2 1 
  4. (integer) 0 
  5. localhost:6379> setbit str:a 7 1 
  6. (integer) 0 
  7. localhost:6379> get str:a 
  8. "a" 
  9. localhost:6379> type str:a 
  10. string 

很明显,Bitmap 底层也是 String 实现,赋值的每一个 bit 均对应 ASCII 码的二进制位。

③HyperLogLog

  1. 127.0.0.1:6379> PFADD hyperLogLog:db "redis" 
  2. (integer) 1 
  3. 127.0.0.1:6379> PFADD hyperLogLog:db "mongodb" 
  4. (integer) 1 
  5. 127.0.0.1:6379> PFADD hyperLogLog:db "mysql" 
  6. (integer) 1 
  7. 127.0.0.1:6379> PFCOUNT hyperLogLog:db 
  8. (integer) 3 
  9. 127.0.0.1:6379> get hyperLogLog:db 
  10. "HYLL\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00H\x91\x80\\g\x84[\x03" 
  11. 127.0.0.1:6379> type hyperLogLog:db 
  12. string 

很明显,HyperLogLog 底层也是 String 实现,与其说 HyperLogLog 是一种单独的数据类型,倒不如说是对 String 数据类型做 API 封装的应用程序。

④归纳

其他几种高级功能类型的验证方式同,这里不做赘述,留给读者自行验证。

这里归纳结论如下:

 

饶了一圈似乎又回到了起点,“说法一:5 种”其实并没有错?毕竟任何类型的底层都是基于 5 种之一实现的。接着往下说。

Talk is cheap, Show me the code.

能说算不上什么,有本事就把你的代码给我看看。

[[387093]]

源码文件列表 

如下图:

 

t_(type) 开头的,有且仅有 6 个,除了“5 种数据类型”外,还包含了:t_stream。

Stream 是 Redis 5.0 版本引入的一个新的数据类型,支持消费者组,借鉴 Kafka 设计的支持多播的可持久化消息队列(支持 group,不支持 partition)。

我们做下验证:

  1. localhost:6379[2]> XADD stream:info * name aku alias bumblebee age 35 address sz 
  2. "1615012000623-0" 
  3. localhost:6379[2]> type stream:info 
  4. stream 

没有问题:6 种,让我们重新梳理一下:

  • String(字符串)
  • List(列表)
  • Set(集合)
  • Sorted Set(有序集合)
  • Hash(哈希)
  • Streams(流信息)

源码就是源码,让人豁然开朗,查谷歌众说纷纭、千篇一律,确实都不对!

那么问题答案到此解决?还没有。但现在已经不是刚刚开始了,只差最后一步。

源码内容

不能徒有其表,只看源码文件列表,不看源码内容。

 

这是关于类型的枚举定义,0 到 6,什么?OBJ_MODULE?这是什么鬼?

请留意这一句描述:

* The "module" object type is a special one that signals that the object

* is one directly managed by a Redis module.

尤其是 special 一词,这是 special 的类型,其余 6 类都是非 special 类型。既然 special,为什么其枚举值是 5 会夹在 hash 和 stream 的非 special 之间?

历史原因,Redis 4.0 引入了模块扩展功能,当时已经认为是最后一个类型。

但是 Redis 5.0 又引入了 Stream 数据结构,可能是觊觎 Kafka 的市场份额,说白跟 RocketMQ 一样都是仿照 Kafka 去实现的。

言归正传,所以该枚举值的定义是不是跟我们日常业务开发的场景似曾相识,因为状态值编号已经被占了,那么新加的状态值就只能往后面排,导致五花八门一点都不连续。没错,就这么接地气。

那么,module 用在什么场景?有很多场景,举个最常用的例子:Leaky Bucket(漏桶算法),也就是 Redis 4.0 引入的 redis-cell 模块。

示例如下:

  1. > cl.throttle module:leaky 14 30 60 1 
  2. 1) (integer) 0          # 0 表示允许  1 表示拒绝 
  3. 2) (integer) 15         # 漏斗容量 capacity 
  4. 3) (integer) 14         # 漏斗剩余空间 left_quota 
  5. 4) (integer) -1         # 如果拒绝了,需要多长时间后再重试,单位秒 
  6. 5) (integer) 2          # 多长时间后,漏斗完全空出来,单位秒 

那么问题答案到此解决?是的,通过分析源码终于有了结论。

结论

Q:Redis 有哪几种数据类型?

A:Redis 6.0 最新版本有且仅有 7 种。

按源码中枚举值定义的顺序,分别为:

  • String(字符串)
  • List(列表)
  • Set(集合)
  • Sorted Set(有序集合)
  • Hash(哈希)
  • Module(模块)
  • Streams(流信息)

Q:高级功能类型,比如 HyperLogLog、Bitmap 等呢?

A:高级功能类型是对数据类型做 API 封装的应用程序。

HyperLogLog、Bitmap、Bloom Filter 的底层都是 String 数据类型,Geospatial 的底层是 Sorted Set 数据类型,cl.throttle(Redis-Cell) 的底层是 Module 数据类型。均可通过 type KEY_NAME 命令逐一核对。

所以,当面试官下次问你“Redis 数据类型的面试 3 连问”时候,可以好好的怼回去了,让面试官看到你的理解、你对底层逻辑的掌握比面试官本人更系统、更专业,给面试官带来些许的惊喜,相信面试效果会完全不一样。

万一惊喜变成了惊吓怎么办?也许该团队是个固执己见的守旧团队,面试官的考题可能也只是来自照本宣科的题库,那么你可以把你的简历慢慢合上,挥一挥衣袖不带走一片云彩。

最后,Talk is cheap,Show me the code。实践才是检验真理的唯一标准,共勉,请不要再错下去了。

作者:大黄蜂

简介:曾就职于华为、腾讯等大型互联网公司,于 2018 年 5 月加盟独角兽公司 akulaku 担任技术管理职务,对分期、金融借贷等核心系统的架构设计具有丰富的实战经验。精通 Redis 和 JVM,非常重视底层原理,对高级用法、协议、源码等具有深入的研究。并且,具有自己独特的团队管理理念,另辟蹊径,专注研发质量和效率,为公司培养出多名青年高潜,并多次荣获各类表彰。

编辑:陶家龙 

征稿:有投稿、寻求报道意向技术人请添加小编微信 gordonlonglong

【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】

 

责任编辑:武晓燕 来源: 51CTO技术栈
相关推荐

2020-02-03 16:52:43

Redis数据结构知道

2021-03-03 00:01:30

Redis数据结双向链表

2021-11-08 09:33:07

JS 字符串数据类型

2019-12-18 14:41:07

Redis数据结构

2010-05-26 17:05:48

MySQL数据类型

2021-04-16 07:28:39

UUIDjavaJava基础

2014-04-25 09:38:08

大数据

2011-07-01 15:32:58

Qt 数据类型

2011-03-31 15:53:39

设计视图Access

2020-12-01 11:50:49

数据库Redis面试

2023-04-27 08:40:55

Redis数据结构存储

2016-08-01 10:42:58

数据类型WebWordPress

2010-07-23 14:18:47

SQL Server数

2019-11-11 14:55:25

Redis数据类型命令

2019-09-27 10:53:28

RedisPythonJava

2024-08-02 13:10:25

2019-11-12 08:53:32

PG数据数据库

2023-07-04 08:41:08

Redis数据类型

2024-11-04 06:20:00

Redis单线程

2021-05-18 07:37:18

前端TypeScript数据类型
点赞
收藏

51CTO技术栈公众号