目录
一 简介
二 数据结构
Redis key 的数据类型都是字符串,value 的类型有以下五种:
序号 | 数据结构 |
---|---|
1 | String(字符串) |
2 | List(列表) |
3 | Set(集合) |
4 | Hash(哈希表) |
5 | ZSet(有序集合) |
2.1 String
- 【简介】
Redis String 存储字节序列,包括文本、序列化对象和二进制数组。String 是 Redis 最基本的数据类型。String 通常用于缓存,但除此之外,它也可以用于实现计数器和执行位运算。 - 【限制】
默认情况下,单个 Redis String 最大为 512MB。 - 【性能】
大部分 Redis String 操作的时间复杂度都是 O(1),SUBSTR、GETRANGE、SETRANGE 的时间复杂度可能是 O(n)。在处理大字符串时,这些随机访问字符串命令可能会导致性能问题。
2.2 List
-
【简介】
Redis list 是字符串值的链表。Redis list 经常用于:(1)实现栈和队列(2)为后台工作系统构建队列管理。Redis list 是通过 linked list 实现的。这意味着即使在一个列表中有数百万个元素,在列表的head 或 tail 添加一个新元素的操作也是在一个固定时间内执行的。使用 LPUSH 命令向包含10个元素的列表的头部添加新元素的速度与向包含1000万个元素的列表的头部添加元素的速度相同。
坏处是什么呢?通过 linked list 实现的列表查询速度不如像通过 array 实现的列表那样快。
-
【常见用例】
List 对于许多任务都很有用,下面是两个非常有代表性的用例:- 记住用户在社交网站上发布的最新更新。
- 进程间通信,使用生产者-消费者模式,其中生产者 push 进列表,消费者消费这些 item 并执行操作。Redis 有特殊的列表命令,可以使该用例更加可靠和高效。
-
【限制】
Redis 列表的最大长度为 2^32 - 1 (4,294,967,295) 个元素。 -
【性能】
访问其头部或尾部的列表操作的复杂度为 O(1),这意味着它们非常高效。然而,操作列表中元素的命令通常是 O(n)。这些示例包括LINDEX、、LINSERT和LSET。运行这些命令时请务必小心,尤其是在大型列表上操作时。 -
【数据结构】
List 的数据结构为 quickList。
在 List 元素较少的时候会使用 ziplist,在元素比较多的时候会使用 quikList。
Redis 将链表和 ziplist 结合起来组成了 quicklist,即将多个 ziplist 使用双向指针串起来使用,这样既满足了快速的插入和删除性能,又不会出现太大的空间冗余。
2.3 Set
- 【简介】
Redis Set 是无序的、去重的。我们可以使用 Redis Set:- Track 唯一的 item(例如:跟踪访问给定博客文章的所有的唯一 IP)。
- 表示关系(例如:具有给定角色的所有用户的集合)。
- 执行常见的集合运算(例如:交集、并集、差集)。
- 【限制】
Redis Set 的最大大小为 2^32 - 1 (4,294,967,295) 个成员。 - 【性能】
大多数集合操作(包括添加、删除以及检查某项是否是集合成员)的复杂度都是 O(1)。这意味着他们的效率很高。但是,对于具有数十万或更多成员的大型集,运行命令时应小心谨慎SMEMBERS。该命令的复杂度为 O(n),并在单个响应中返回整个集合。作为替代方案,请考虑SSCAN,它允许您迭代地检索集合的所有成员。 - 【数据结构】
Set 数据结构是字典,字典是用 hash 表实现的。
Java 中的 HashSet 的内部实现使用 HashMap,只不过所有的 value 都指向同一个对象。 Redis 的 set 结构也是一样的,它的内部也使用 hash 结构,所有的 value 都指向同一个内部值。
2.4 Hash
-
【简介】
Redis Hash 是一个键值对集合。可以使用 Hash 表示基本对象并存储计数器分组等。Redis Hash 是一个 String 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。 类似于 java 里面的 Map<String,Object>。
-
【性能】
大多数 Redis 哈希命令的复杂度都是 O(1)。
一些命令 - 例如HKEYS、HVALS和HGETALL- 的复杂度为 O(n),其中n是字段值对的数量。
- 【限制】
每个哈希最多可以存储 4,294,967,295 (2^32 - 1) 个字段值对。实际上,您的哈希值仅受托管 Redis 部署的虚拟机上的总内存的限制。 - 【数据结构】
Hash 类型对应的数据结构是 2 种:ziplist(压缩列表),hashtable(哈希表)。
当 field-value 长度较短个数较少时,使用 ziplist,否则使用 hashtable。
2.5 ZSet
-
【简介】
Redis 排序集是按关联分数排序的 Set 集合。当多个字符串具有相同分数时,字符串按字典序排序。排序集的一些用例包括:- 排行榜。例如,你可以使用 sorted set 来轻松地维护大型在线游戏中最高分的有序列表。
- 速率限制器。尤其是,您可以使用 sorted set 来构建滑动窗口速率限制器,以防止过多的 API 请求。
你可以将排序集看作是 Set 和 Hash 的混合。与集合类似,排序集合由唯一的、不重复的字符串元素组成,因此在某种意义上,排序集合也是一个集合。
然而,虽然集合内的元素没有排序,但排序集合中的每个元素都与一个称为分数的浮点值相关联 (这就是为什么该类型也类似于散列,因为每个元素都映射到一个值)。
此外,排序集中的元素是按顺序获取的(因此它们不是根据请求排序的,顺序是用于表示排序集的数据结构的特性)。它们根据以下规则排序:
- 如果 B 和 A 是具有不同分数的两个元素,则如果 A.score > B.score,则 A > B。
- 如果 B 和 A 的分数完全相同,则如果 A 字符串按字典顺序大于 B 字符串,则 A > B。B 和 A 字符串不能相等,因为排序集仅具有唯一元素。
-
【性能】
大多数排序集操作的复杂度为 O(log(n)),其中n是成员数。ZRANGE运行具有较大返回值(例如,数万或更多)的命令时请务必小心。该命令的时间复杂度为 O(log(n) + m),其中m是返回结果的数量。
-
【数据结构】
SortedSet(zset) 是 redis 提供的一个非常特别的数据结构,内部使用到了 2 种数据结构,hash 表与跳表。- hash 表。类似于 java 中的 Map<String,score>,key 为集合中的元素,value 为元素对应的 score,可以用来快速定位元素定义的 score,时间复杂度为 O(1)。
- 跳表(skiplist)。跳表是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为 O(logN)。类似 java 中的 ConcurrentSkipListSet,根据 score 的值排序后生成的一个跳表,可以快速按照位置的顺序或者 score 的顺序查询元素。
2.6 BitMaps
BitMaps 不是实际的数据类型,而是在 String 类型上定义的一组面向位的操作,这些操作被视为位向量。由于字符串是二进制安全的 blobs,其最大长度为512MB,因此它们适合设置为2 ^ 32个不同的位。
您可以对一个或多个字符串执行按位操作:
- 对于集合成员对应于整数 0-N 的情况,有效的集合表示。
- 对象权限,其中每个位表示特定权限,类似于文件系统存储权限的方式。
位图的最大优点之一是,它们在存储信息时通常可以极大地节省空间。例如,在一个系统中,不同的用户由增量的用户 ID 表示,记住 40 亿用户的一个位信息(例如,知道一个用户是否想要接收新闻通讯)可能只需要 512MB 的内存。
2.7 概率数据结构
2.7.1 HyperLoglog
HyperLogLog 是一种概率数据结构,用于估计集合的基数。作为一种概率数据结构,HyperLogLog 以完美的准确性换取高效的空间利用。
HyperLoglog 的应用场景,例如:统计网站的 UV 等(这一天该页面的独立访问次数有多少?有多少独立用户播放过这首歌?有多少独立用户观看过该视频?)。求集合中不重复元素的个数的问题称为基数问题。
- 每个时间段的每页(视频/歌曲)都会创建一个 HyperLogLog,并且每次访问时都会将每个 IP/标识符添加到其中。
HyperLoglog 的优点:每个 HyperLoglog 键只需要 12KB 内存就可以计算最多 2^64 个不同元素的基数。
2.7.2 布隆过滤器
三 Redis 的发布与订阅(Pub/Sub)
发布与订阅是一种消息通信模式,发布者发布消息,订阅者接收消息。