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

网友投稿 916 2023-05-27

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

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

图片来自 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 种的说法。

从官网找答案

请留意这一句:

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

localhost:6379> set str:hello world OK localhost:6379> get str:hello "world" localhost:6379> type str:hello string

②Bitmap

localhost:6379> setbit str:a 1 1 (integer) 0 localhost:6379> setbit str:a 2 1 (integer) 0 localhost:6379> setbit str:a 7 1 (integer) 0 localhost:6379> get str:a "a" localhost:6379> type str:a string

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

③HyperLogLog

127.0.0.1:6379> PFADD hyperLogLog:db "redis" (integer) 1 127.0.0.1:6379> PFADD hyperLogLog:db "mongodb" (integer) 1 127.0.0.1:6379> PFADD hyperLogLog:db "mysql" (integer) 1 127.0.0.1:6379> PFCOUNT hyperLogLog:db (integer) 3 127.0.0.1:6379> get hyperLogLog:db "HYLL\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00H\x91\x80\\g\x84[\x03" 127.0.0.1:6379> type hyperLogLog:db string

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

④归纳

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

这里归纳结论如下:

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

Talk is cheap, Show me the code.

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

源码文件列表

如下图:

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

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

我们做下验证:

localhost:6379[2]> XADD stream:info * name aku alias bumblebee age 35 address sz "1615012000623-0" localhost:6379[2]> type stream:info 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 模块。

示例如下:

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:不可忽视的MySQL字符集
下一篇:Redis 分布式锁遇到的序列化问题
相关文章