目录
21.Redis一般有哪些使用场景?
比如:
热点数据的缓存
缓存是Redis最常见的应用场景,之所以这么使用,主要是因为Redis读写性能优异。而且逐渐有取代memcached,成为首选服务端缓存的组件。而且,Redis内部是支持事务的,在使用的时候能有效保证数据的一致性。
限时业务的运用
Redis中可以使用expire命令设置一个键的生存时间,到时后Redis会删除它。利用这一特性可以运用在限时的优惠活动,收集验证码等业务场景。
计数器相关问题
Redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动,分布式序列号的生成,具体业务还体现在比如限制多少请求,一个接口一天限制调用多少次等等。
分布式锁
这个主要利用Redis的setnx命令进行,setnx:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0,主要用在比如秒杀系统等。
22.Redis有哪些数据类型?
5种基础数据类型,分别是:String,List,Set,ZSet,Hash。
三种特殊的数据类型分别是HyperLogLogs(基数统计),Bitmaps(位图)和geospatial(地理位置)。
23.谈谈Redis的对象机制(RedisObject)?
比如说,集合类型就可以由字典和整数集合两种不同的数据 结构实现,但是 ,当用户执行ZADD命令时,他/她应该不必关心集合使用的是什么编码,只要Redis能按照ZADD命令的指示,将新元素添加到集合就可以了。
这说明,操作数据类型的命令除了要对键的类型进行检查之外,还需要根据数据类型的不同编码进行多态处理。
为了解决以上问题,Redis构建了自己的类型系统,这个系统的主要功能包括:
RedisObject对象。
基于RedisObject对象的类型检查。
基于RedisObject对象的显示多态函数。
对RedisObject进行分配,共享和销毁的机制。
下图对应上面的结构:
24.redis数据类型有哪些底层数据结构?
简单动态字符串-sds
压缩列表-zipList
快表-QuickList
字典/哈希表-Dict
整数集-inSet
跳表-ZSkipList
25.为什么要设计sds?
常数复杂度获取字符串长度
由于len属性的存在,我们获取SDS字符串的长度只需要读取len属性,事件复杂度o(1)。而对于C语言,获取字符串的长度通常是经过遍历技术来实现的,事件复杂度为o(n)。通过strlen key命令可以获取key的字符串长度。
杜绝缓冲区溢出
我们知道在C语言中使用strcat函数来进行两个字符串的拼接,一单没有分配足够长度的内存空间,就会造成缓存区溢出。而对于SDS数据类型,在进行字符修改的时候,会首先根据记录的len属性检查内存空间是否满足需求,入过不满足,会进行相应的空间扩展,然后在进行修改操作,所以不会出现缓冲区溢出。
减少修改字符串的内存重新分配次数
C语言由于不记录字符串的长度,所以如果要修改字符串,把必须要重新分配内存(先释放再申请),因为如果没有重新分配,字符串长度增大时会造成内存缓冲区溢出,字符串长度减小时会造成内存泄漏。
而对于SDS,由于len属性和alloc属性的存在,对于修改字符串SDS实现了空间预分配和惰性空间释放两种策略:
1.空间预分配:
对字符串进行空间扩展的时候,扩展的内存比实际需要的多,这样可以减少连续执行字符串增长操作所需要的内存重分配次数。
2.惰性空间释放:
对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用alloc属性将这些字节的数量记录下来,等待后续使用。(当然SDS也提供了相应的api,当我们有需要时,也可以手动释放这些未使用的空间)。
二进制安全
因为C字符串以空字符作为字符串结束的标识,而对于一些二进制文件(如图片等),内容可能包括空字符串,因此C字符串无法正确存取;而所有SDS的API都是以处理二进制的方式来处理buf里面的元素,并且SDS不是以空字符串来判断是否结束,而是以len属性表示的长度来判断字符串是否结束。
兼容部分C字符串函数
虽然SDS是二进制安全的,但是一样最从每个字符串都是以空字符串结尾的惯例,这样子可以重用C语言库<string.h>中的一部分函数。