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

String:

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

如果 value 值是一个整数,还可以对它进行自增操作。自增是有范围的,它的范围是
signed long 的最大最小值,超过了这个值

List

Redis 的列表相当于 Java 语言里面的 LinkedList,注意它是链表而不是数组。这意味着
list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为
O(n)
lindex 相当于 Java 链表的 get(int index)方法,它需要对链表进行遍历,性能随着参数
index 增大而变差
实际是那个redis 链表使用的是一种 快速链表 quicklist 的一个结构。

Redis中是采用sdlist和ziplist来实现quicklist的,其中sdlist充当map中控器的作用(其主要用在实现列表键、事务模块保存输入命令和服务器模块),
ziplist充当占用连续内存空间数组的作用。quicklist本身是一个双向无环链表,它的每一个节点都是一个ziplist。

- 双向链表在插入节点上复杂度很低,但它的内存开销很大,每个节点的地址不连续,容易产生内存碎片。
- ziplist是存储在一段连续的内存上,存储效率高,但是它不利于修改操作,插入和删除数都很麻烦,
复杂度高,而且其需要频繁的申请释放内存,特别是ziplist中数据较多的情况下,搬移内存数据太费时!

redis zset长度限制 redis zset 容量_Redis

应用场景:Redis 的列表结构常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符
串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理。

Hash

Redis 的字典相当于 Java 语言里面的 HashMap,它是无序字典。内部实现结构上同
Java 的 HashMap 也是一致的,同样的数组 + 链表二维结构。第一维 hash 的数组位置碰撞
时,就会将碰撞的元素使用链表串接起来。

redis zset长度限制 redis zset 容量_Redis_02

不同的是,Redis 的字典的值只能是字符串,另外它们 rehash 的方式不一样Redis
为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。
渐进式rehash:

在redis中,扩展或收缩哈希表需要将 ht[0] 里面的所有键值对 rehash 到 ht[1] 里面, 但是, 这个 rehash 动作并不是一次性、集中式地完成的, 而是分多次、渐进式地完成的。为了避免 rehash 对服务器性能造成影响, 服务器不是一次性将 ht[0] 里面的所有键值对全部 rehash 到 ht[1] , 而是分多次、渐进式地将 ht[0] 里面的键值对慢慢地 rehash 到 ht[1] 。
以下是哈希表渐进式 rehash 的详细步骤:
(1)为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。
(2)在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。
(3)在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。
(4)随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。

渐进式 rehash 的好处在于它采取分而治之的方式, 将 rehash 键值对所需的计算工作均滩到对字典的每个添加、删除、查找和更新操作上, 从而避免了集中式 rehash 而带来的庞大计算量。

参考:

set

Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的
内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL。
当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。 set 结构可以用来
存储活动中奖的用户 ID,因为有去重功能,可以保证同一个用户不会中奖两次。

zset

zset 可能是 Redis 提供的最为特色的数据结构,它也是在面试中面试官最爱问的数据结
构。它类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部
value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权
重。它的内部实现用的是一种叫着 skipList「跳跃列表」的数据结构。

skipList:

跳表是有序链表,即使对于排过序的链表,我们对于查找还是需要进行通过链表的指针进行遍历的,时间复杂度很高依然是O(n)
因为 zset 要支持随机的插入和删除,所以它不好使用数组来表示,没法直接使用二分法,跳表就是链表与二分法的结合

redis zset长度限制 redis zset 容量_redis zset长度限制_03