String
String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以 修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配
如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。
List
单键多值
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
List的数据结构为快速链表quickList。
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。
它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。
因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。
Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist使用双向指 针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Set
对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储1个列表数据,又不希望出现重复数据时,set是一个很好的选择
Set数据结构是dict字典,字典是用哈希表实现的。
Java中HashSet的内部实现使用的是 HashMap,只不过所有的 value 都指向同一个对象。Redis的 set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
Hash
hash是一个键值对集合。
Redis hash是一个string类型的field和value的映射表,hash 特别适合用于存储对象。 类似 Java 里面的 Map<String:Object>
Hash 类型对应的数据结构是两种: ziplist (压缩列表) , hashtable (哈希表)。当 field · value 长度较短且个数较少时,优用 ziplist ,否则使用 hashtable
ZSet
SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构 Map<String,Doublep,可以给每一个元素 value 赋予一个权重score,另 一方面它又类似于TreeSet,内部的元素会按照权重score 进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset 底层使用了两个数据结构
(1)hash,hash的作用就是关联元素 value 和权重 score,保障元素 value的唯 一性,可以通过元素 value 找到相应的score值。
(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
跳表
1、简介
有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。
2、实例
对比有序链表和跳跃表,从链表中查询出51
(1)有序链表
要查找值为51的元素,需要从第一个元素开始依次查找、比较才能找到。共需要6次比较。
(2)跳跃表
从第2层开始,1节点比51节点小,向后比较。
21节点比51节点小,继续向后比较,后面就是NULL了,所以从21节点向下到第1层在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从41向下。
在第0层,51节点为要查找的节点,节点被找到,共查找4次。
从此可以看出跳跃表比有序链表效率要高