带你整理面试过程中关于 Redis 的五种数据类型
Posted 南淮北安
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你整理面试过程中关于 Redis 的五种数据类型相关的知识,希望对你有一定的参考价值。
文章目录
一、Redis 优缺点
Redis (Remote Dictionary Server) 是一个使用 C 语言 编写的,开源的 (BSD许可) 高性能 非关系型 (NoSQL) 的 键值对数据库。
NoSQL :不仅仅是数据库,对传统数据库的补充
键值对结构:查找和操作的时间复杂度都是O(1)
Redis中的主要数据结构有动态字符串(SDS),链表,字典等,但是并没有直接使用这些数据结构实现键值对数据库,而是基于这些数据结构创建了一个对象系统,包括:字符串对象、列表对象,哈希对象,集合对象和有序集合对象,好处就是可以针对不同的使用场景,为对象设置多种不同的数据结构,从而提高对象在不同场景下的使用效率。
还有:Bitmap(位图)、HyperLogLog(超级日志)和Geospatial(地理空间)
优点:
a. 读写性能优异:Redis能读的速度是 110000 次/s,写的速度是 81000 次/s。
b. 支持数据持久化:支持 AOF 和 RDB 两种持久化方式。
c. 支持事务:Redis 的所有操作都是原子性的,同时 Redis 还支持对几个操作合并后的原子性执行。
d. 数据结构丰富,支持字符串,列表,哈希,集合等多种数据结构。
e. 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点:
a. 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis 适合的场景主要局限在较小数据量的高性能操作和运算上。
b. Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,降低了 系统的可用性。
c. Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
二、Redis 的对象类型和编码
Redis使用对象来表示数据库中的键和值,每次当我们在Redis的数据库中新创建一个键值对时,我们至少会创建两个对象,一个对象用作键值对的键(键对象),另一个对象用作键值对的值(值对象)。
比如:SET命令在数据库中创建了一个新的键值对,其中键值对的键是一个包含了字符串值"msg"的对象,而键值对的值则是一个包含了字符串值"hello world"的对象
对于 Redis 数据库保存的键值对来说,键总是一个字符串对象,值可以是字符串对象,列表对象,哈希对象,集合对象或者有序集合对象。
当我们称呼一个数据库键为“字符串键”时,我们指的是“这个数据库键所对应的值为字符串对象”;
当我们称呼一个键为“列表键”时,我们指的是“这个数据库键所对应的值为列表对象”。
Redis中的每个对象都由一个redisObject结构表示,该结构中和保存数据有关的三个属性分别是type属性、encoding属性和ptr属性:
对象的 type 属性记录了对象的类型,得到的是值对象的类型,而不是键对象的类型
对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。
encoding属性记录了对象所使用的编码,也即是说这个对象使用了什么数据结构作为对象的底层实现,这个属性的值可以是表列出的常量的其中一个。
每种类型的对象都至少使用了两种不同的编码
通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的使用场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。
设置不同的编码就是此时采用什么数据结构作为对象的底层实现
比如:列表有压缩列表和链表两种底层实现
因为压缩列表比双端链表更节约内存,并且在元素数量较少时,在内存中以连续块方式保存的压缩列表比起双端链表可以更快被载入到缓存中;
随着列表对象包含的元素越来越多,使用压缩列表来保存元素的优势逐渐消失时,对象就会将底层实现从压缩列表转向功能更强、也更适合保存大量元素的双端链表上面;
其他类型的对象也会通过使用多种不同的编码来进行类似的优化。
三、五种数据类型
1. String 字符串
字符串对象的编码可以是int、raw或者embstr。
如果对象的长度大于32则会将对象的编码设置为raw,如果小于32则会将对象的编码设置为 embstr
底层对象:整数集合,SDS动态字符串
String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。
使用:get 、 set 、 del 、 incr、 decr 等
实战场景:
(1)缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。
(2)计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
2. Hash (哈希)
哈希对象的编码可以是ziplist或者hashtable。
底层实现可以是:压缩列表,字典
哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;同时哈希对象保存的键值对数量小于512个,使用压缩列表作为底层数据结构
其余情况采用字典作为底层实现
是一个map,指值本身又是一种键值对结构
使用:所有hash的命令都是 h 开头的 hget 、hset 、 hdel 等
实战场景:
缓存: 能直观,相比string更节省空间的维护缓存信息,如用户信息,视频信息等。
3. 列表
列表对象的编码可以是ziplist或者linkedlist。
底层是:压缩列表和链表
当列表对象保存的所有字符串长度都小于64字节,同时列表保存的元素数量小于512时,会采用压缩列表作为底层。
其余情况使用链表作为底层实现
List 说白了就是链表(redis 使用双端链表实现的 List),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除数据。
实战场景:
timeline:例如微博的时间轴,有人发布微博,用lpush加入时间轴,展示新的列表信息;交易网站上架新品(存储最新上架的前100名)
4. Set 集合
集合对象的编码可以是intset或者hashtable。
底层实现可以是:整数集合,字典
集合对象保存的所有元素都是整数值;同时集合对象保存的元素数量不超过512个,采用整数集合作为底层实现
其余情况采用字典作为底层实现
集合类型也是用来保存多个字符串的元素,
但和列表不同的是集合中不允许有重复的元素;集合中的元素是无序的,不能通过索引下标获取元素;支持集合间的操作,可以取多个集合取交集、并集、差集。
实战场景:
(1)标签(tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以推荐相同的消息。
(2)点赞,或点踩,收藏等,可以放到set中实现
5. zset 有序集合
有序集合的编码可以是 ziplist 或者 skiplist。
底层实现可以是:压缩列表,跳跃表
对于跳跃表的底层实现是有序集合元素同时被保存在跳跃表和字典中
有序集合可以单独使用字典或者跳跃表的其中一种数据结构来实现,但无论单独使用字典还是跳跃表,在性能上对比起同时使用字典和跳跃表都会有所降低。
举个例子,如果我们只使用字典来实现有序集合,那么虽然以O(1)
复杂度查找成员的分值这一特性会被保留,但是,因为字典以无序的方式来保存集合元素,所以每次在执行范围型操作程序都需要对字典保存的所有元素进行排序,完成这种排序需要至少O(NlogN)
时间复杂度,以及额外的O(N)
内存空间(因为要创建一个数组来保存排序后的元素)。
另一方面,如果我们只使用跳跃表来实现有序集合,那么跳跃表执行范围型操作的所有优点都会被保留,但因为没有了字典,所以根据成员查找分值这一操作的复杂度将从O(1)
上升为O(logN)
因为在这个范围内快速定位是二分查找,所以时间复杂度是O(logN)
因为以上原因,为了让有序集合的查找和范围型操作都尽可能快地执行,Redis选择了同时使用字典和跳跃表两种数据结构来实现有序集合
有序集合保存的元素数量小于128个;同时有序集合保存的所有元素成员的长度都小于64字节;才会使用压缩列表作为底层实现
有序集合和集合有着必然的联系,保留了集合不能有重复成员的特性,区别是,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据。
(有序集合中的元素不可以重复,但是score 分数 可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)。
有序集合存储的是一个键key,一个对应的有序集合
当通过key查找具体的分数时,是先通过key找到对应的有序集合,然后再字典定位到具体的score
实战场景:
排行榜:有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。
详细内容参考:Redis 的五种数据结构
其他:位图(Bitmap),超级日志(HyperLogLog),地理空间(Geospatial)
Bitmap:通过操作二进制位记录数据
HyperLogLog:被用于估计一个Set中元素数量的概率性的数据结构。
Geospatial:用于地理空间关系计算
以上是关于带你整理面试过程中关于 Redis 的五种数据类型的主要内容,如果未能解决你的问题,请参考以下文章
带你整理面试过程中关于Redis 主从模式哨兵模式和集群模式详解的相关知识点