Redis初始给了我们16个库,数据都是以键—值对来存储的,其中键的数据结构固定为string,值的数据类型有五种分别为:string、list、set、hash、zset。
1.string(字符串)
string是最简单常用的数据结构,不同的类型有不同的编码格式:
- 整数类型,字符串对象的编码格式为int。
- 短字符串长度<=44,字符串对象的编码格式为embstr。
- 长字符串长度>44,字符串对象的编码格式为raw。
最常用的就是计数器,比如文章点赞量、访问量等等。
2.list (列表)
list是可重复的列表,是按插入的顺序排序的,实现方式有两种分别是ziplist和quicklist。
2.1ziplist实现list
在list中元素数量较少的情况下采用的是压缩链表ziplist存储,ziplist内存占用的是一块连续空间,利用数组实现,可以存字符串和整数,其内部有ziplist占用字节的总数、元素的总个数、首尾的偏移量。首尾的偏移量用来快速定位到最后一个元素,可用于从后往前遍历。
2.2quicklist实现list
quick是一个双向链表,是基于ziplist实现的,其内部的每一个结点都是ziplist,用于list元素数量大于512时存储。
list主要被用于像展现粉丝列表、关注列表等等。
3.set(集合)
set是无序不可重复,无序只是表明不保证按插入顺序存储,实现方式有两种分别是inset和hashtable。
3.1inset实现set
inset内部也是一块连续的内存空间,利用数组来实现,用于集合中元素数量较少的情况,而且只能存储整数,为的是节约内存而提高效率,如果有非整数内部的实现就会立刻变为hashtable结构。
3.2hashtable实现set
如果元素数量大于512个,使用hashtable来存储,实现set集合只使用了hashtable中的键,值为null,可以快速查询到需要的数据。
set可用做存储商品的标签,后续用于并、交、差操作。
4.hash(散列)
redis中的散列可以存储多个键值对,实现方式有ziplist和hashtable。
4.1ziplist实现hash
可以使用两个ziplist来实现hash,一个存储键(field),另一个存储值(vlaue),用于键值对中的字符串长度小于64并且元素数量较少的情况。
4.2hashtable实现hash
当键值对的字符串长度大于64或者元素数量大于512时,使用hashtable来实现即可。
hash可用做存储用户购买的商品、购物车,比如用户的id为key,然后商品的id为field,购买商品的数量为value。
5.zset
zset是排好序(默认由大到小)的集合,和散列一样,只不过value存储的是score分数,是按照分数来排序的,有序集合的实现方式有ziplist和skiplist(跳表)。
5.1ziplist实现zset
当元素数量小于128并且键值小于64字节时可以使用两个紧挨的ziplist来实现zset,元素有序是因为当新增一个元素时,需要扩大内存以及从前到后一个个进行元素比对最终找到合适的插入位置,其中会涉及到元素的移动,最坏情况下如果扩大内存时,后面的内存不是空闲的,这就会涉及到整个ziplist的数据重新迁移。
5.2skiplist实现zset
跳表是在压缩列表的基础上增加了多级索引,其寻址的过程为:从最高层开始开始查找,如果当前位置的next指针为null,那么就下降到下一层,如果next指向的元素小于查找的值,那么就继续向后去遍历查找,如果大于查找的值,那么就调用backward后退指针指向next位置的前一个元素,向前去比较寻找即可。如下图二级索引示例查找27:
至于为什么不使用平衡二叉树来实现zset的一部分原因是因为其每个节点都需要指向左右子树的2个指针 ,而使用skiplist平均每个元素需要1.3个指针,我们都知道局限redis的会是内存空间大小和网络速度,所以使用skiplist会更加的节省内存空间。
zset最主要的使用场景就是排行榜。