Redis的基本数据结构
数据结构
- string(字符串)
Redis的字符串是动态字符串,是可以修改的字符串,内部结构类似Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配
当字符串长度小于1M时,成倍扩容,超过1M每次扩容1M,最大长度为512M
可用于缓存用户信息
- list(列表)
Redis中的list相当于Java的LinkedList,插入和删除为 O(1) ,索引定位很慢,时间复杂度为 O(n)
list结构可用作异步队列,将需要延后处理的任务结构体序列化成字符串塞进Redis的列表。
- hash(字典)
相当于Java的HashMap,是无序字典,是数组加链表的结构
不同的是:hash的值只能是字符串,且他们的rehesh不同,HashMap在字典很大时,rehash是一个耗时的工作,需要一次性全部rehash。Redis为了高性能防止阻塞服务,采用了渐进式rehash策略,即在rehash的同时保存新旧两种结构,查询时会同时查询两个hash结构,然后在后续的定时任务以及hash的子指令中,循序渐进的将旧hash的内容一点点迁移到新的hash结构中。
缺点:hash结构的存储消耗要高于单个字符串
- set(集合)
Redis的集合相当于Java语言的HashSet,内部的键值对是无序且唯一的,相当于一个特殊的hash,value为NULL。
可用于存储活动中奖用户的ID,保证同一个用户不会中奖两次
- zset(有序列表)
类似于 Java 的 SortedSet 和 HashMap 的结合体,可以为每个值赋予一个排序权重 score。内部实现是用跳表或者压缩列表来实现的
可用于存储 粉丝列表 value的值为粉丝ID,score是关注时间
压缩列表
当zset 保存的元素少于128个并且所有元素都小于64字节时,编码为ziplist
此时的有序集合对象使用压缩列表作为底层实现
每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。并且压缩列表内的集合元素按分值从小到大的顺序进行排列,小的放置在靠近表头的位置,大的放置在靠近表尾的位置。字典的键保存元素的值,字典的值则保存元素的分值。
跳表:
- 跳表是一个随机化的数据结构,实际上就是一种可以进行二分查找的有序链表;
- 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找
- 跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能O(log n)
- 跳跃表节点的 object 属性保存元素的成员,跳跃表节点的 score 属性保存元素的分值。
- 通过指针来共享相同元素的成员和分值,所以不会产生重复,造成内存的浪费
为什么使用跳表而不是使用红黑树来实现
redis的有序集合支持
- 插入元素
- 删除元素
- 查找元素
- 有序输出所有元素
- 查找区间内所有元素
前四项红黑树都可以完成,且时间复杂度与跳表相同,但是对于最后一项红黑树的效率没有跳表高。
在跳表中,要查找区间的元素,我们只要定位到两个区间端点在最底层的位置,然后遍历即可,而红黑树只能定位到端点后再从首位置开始每次都要查找后续节点,相对来说比较耗时
此外,跳表的实现相对比较容易且易读,红黑树实现起来比较困难,所以Redis选择使用跳表来实现有序集合