Redis的五种基础数据结构

Redis有5种基础数据结构,分别为:String(字符串),list(列表),hash(字典),set(集合)和zset(有序集合)。

1.String(字符串)

字符串的结构

字符串String是Redis最简单的数据结构,它的内部表示就是一个字符数组。redis中,所有的数据结构都以唯一的key字符串作为名称,然后通过这个唯一的key值来获取相应的value数据。不同类型的数据结构的差异就在于value的结构不一样。

Redis中的字符串是动态字符串,是可以修改的字符串,内部结构的实现类似于java中的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。内部为当前字符串分配的实际空间capacity一般要高于实际字符串长度len。当字符串长度小于1MB时,扩容都是加倍现有的空间。当字符串长度超过1MB时,扩容时,一次只会多扩1MB的空间。

Redis 数据结构 集合 redis基本数据结构_redis


注:Redis规定了字符串的长度不能超过512MB。

字符串基本操作

键值对

Redis 数据结构 集合 redis基本数据结构_字符串_02


其他操作可参考菜鸟教程 https://www.runoob.com/redis/redis-tutorial.html

批量键值对

Redis 数据结构 集合 redis基本数据结构_Redis_03


过期和set命令扩展

可以对 key 设置过期时间,到时间会被自动删除,这个功能常用来控制缓存的失效时间

Redis 数据结构 集合 redis基本数据结构_redis_04


计数

如果 value 是一个整数,还可以对它使用 INCR 命令进行 原子性 的自增操作,这意味着及时多个客户端对同一个 key 进行操作,也决不会导致竞争的情况

Redis 数据结构 集合 redis基本数据结构_Redis_05

字符串的一些使用场景

1.计数器
string类型的incr和decr命令的作用是将key中储存的数字值加一/减一,这两个操作具有原子性,总能安全地进行加减操作,因此可以用string类型进行计数,如微博的评论数、点赞数、分享数,抖音作品的收藏数,京东商品的销售量、评价数等。
2.存储对象
利用JSON的字符串和对象之间的相互转换来实现
3.分布式锁(在后面的分布式锁章节再讲)

2.list(列表)

列表的结构

Redis 的列表相当于 Java 语言中的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n)。
Redis的列表结构常用来做异步队列使用,将需要延后处理的任务结构体序列化成字符串,塞进Redis的列表,另 个线程从这个列表中轮询数据进行处理。

列表基本操作

Redis 数据结构 集合 redis基本数据结构_Redis 数据结构 集合_06


队列(右边进左边出)

队列是先进先出的数据结构,常用于消息排队和异步逻辑处理,它会确保元素的访问顺序性。

Redis 数据结构 集合 redis基本数据结构_字符串_07


栈(右边进右边出)

栈是先进后出的数据结构,跟队列正好相反 Redis 的列表数据结构来做栈使用的业务场景并不多见。

Redis 数据结构 集合 redis基本数据结构_Redis 数据结构 集合_08

列表的一些使用场景

1.消息队列:通过Lpush命令从左边插入数据,使用BRpop命令阻塞的“抢”列表尾部的数据。
2.文章列表或者数据分页展示的应用。

3.hash(字典)

字典的结构

Redis 中的字典相当于 Java 中的 HashMap,内部实现也差不多类似,都是通过 “数组 + 链表” 的链地址法来解决部分 哈希冲突,同时这样的结构也吸收了两种不同数据结构的优点。

渐进rehash策略:

Java HashMap在字典很大时 rehash 是个耗时的操作,需要一次性全部rehash,Redis为了追求性能,不能堵塞服务,所以采用渐进rehash策略。

渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 结构,如下图所示,查询时会同时查询两个 hash 结构,然后在后续的定时任务以及 hash 操作指令中,循序渐进的把旧字典的内容迁移到新字典中。当搬迁完成了,就会使用新的 hash 结构取而代之。

Redis 数据结构 集合 redis基本数据结构_Redis 数据结构 集合_09


扩缩容的条件

正常情况下,当 hash 表中 元素的个数等于第一维数组的长度时,就会开始扩容,扩容的新数组是 原数组大小的 2 倍。不过如果 Redis 正在做 bgsave(持久化命令),为了减少内存也得过多分离,Redis 尽量不去扩容,但是如果 hash 表非常满了,达到了第一维数组长度的 5 倍了,这个时候就会 强制扩容。

当 hash 表因为元素逐渐被删除变得越来越稀疏时,Redis 会对 hash 表进行缩容来减少 hash 表的第一维数组空间占用。所用的条件是 元素个数低于数组长度的 10%,缩容不会考虑 Redis 是否在做 bgsave。

字典的基本操作

hash 也有缺点,hash 结构的存储消耗要高于单个字符串,所以到底该使用 hash 还是字符串,需要根据实际情况再三权衡。并且hash的使用场景也比较少。

Redis 数据结构 集合 redis基本数据结构_数据库_10

字典的一些使用场景

1.购物车
2.存储对象

4.set(集合)

set(集合)的结构

Redis 的集合相当于 Java 语言中的 HashSet,它内部的键值对是无序、唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL。
当集合中的最后一个元素被移除后,数据结构会被自动删除,内存被回收。

set(集合)基本操作

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200615203417565.png

Redis 数据结构 集合 redis基本数据结构_字符串_11


这里可以看出不能重复,且无序。

set(集合)的一些使用场景

1.标签
比如我们博客网站常常使用到的兴趣标签,把一个个有着相同爱好,关注类似内容的用户利用一个标签把他们进行归并。
2. 好友/关注/粉丝/感兴趣的人集合
3.随机展示

5.zset(有序集合)

zset(有序集合)的结构

zset 可能是 Redis 提供的最有特色的数据结构,如下图所示,它类似于 Java 的SortedSet 和HashMap的结合体, 一方面它是个 set ,保证了内部 value 的唯性,另方面它可以给每个 value 赋予一个 score ,代表这个 value 的排序权重。它的内部实现用的是一种叫作“跳跃列表”的数据结构。跳跃表比较复杂,这里就不讲解跳跃表内部结构原理了,后面有机会可以深入学习。

Redis 数据结构 集合 redis基本数据结构_数据库_12

zset(有序集合)基本操作

Redis 数据结构 集合 redis基本数据结构_字符串_13

zset(有序集合)的一些使用场景

1.排行榜

参考文章

1.《Redis 深度历险》 - https://book.douban.com/subject/30386804/
2. https://mp.weixin.qq.com/s/MT1tB2_7f5RuOxKhuEm1vQ