Redis 面试题
解压后的文件:
redis.windows.conf 配置文件
redis-cli.exe 客户端
redis-server.exe: 服务器端
数据结构:
1、字符串类型: string
2、哈希类型:hash(map格式:hashmap)
3、列表:list(linkedlist格式)
4、集合类型:set(hashset)
5、有序集合类型:sortedset
字符串类型操作:
存储:set key value
获取:get key
删除:del key
哈希类型操作:
存储:hset key field value
获取: hget key field
删除:hdel key field
获取哈希全部:hgetall key
列表类型:
添加
lpush key value:将元素加入列表左边
rpush key value:将元素加入列表右边
获取:lrange key start end :范围获取
删除:
lpop key :删除列表最左边的元素,并将元素返回
rpop key:删除列表最右边的元素,并将元素返回
集合类型set:不允许重复元素
存储:sadd key value
获取:smembers key 获取set集合中的所有元素
删除:srem key value 删除set集合中的某个元素
有序集合类型 sortedset:不允许重复元素,且元素有顺序
存储:zadd key score value score分数越低排名越前面
获取:zrange key start end (zrange key start end withscores) :0 -1 是取所有的数据
删除:zrem key value
1、缓存穿透:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求
解决方案:
1、接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
2、从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
2、缓存击穿:缓存击穿是指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。
解决方案:
1、设置热点数据永远不过期。
2、加互斥锁,互斥锁
3、设置自动服务去缓存数据
3、缓存雪崩: 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
3、设置热点数据永远不过期。
4、设置自动服务去缓存数据
4、Redis 持久化方案:
Rdb 和 Aof
5、Redis是单线程的,但Redis为什么这么快?
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
6、Redis相比memcached有哪些优势:
memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
redis的速度比memcached快很多
redis可以持久化其数据
7、RDB和AOF的优缺点
RDB持久化
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
8、Redis还提供的高级工具
像慢查询分析、性能测试、Pipeline、事务、Lua自定义命令、Bitmaps、HyperLogLog、发布/订阅、Geo等个性化功能
9、布隆过滤器
bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小
10、redis加锁分类
redis能用的的加锁命令分表是INCR、SETNX、SET
1、第一种锁命令INCR
这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。
然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。
2、第二种锁SETNX
这种加锁的思路是,如果 key 不存在,将 key 设置为 value
如果 key 已存在,则 SETNX 不做任何动作
3、第三种锁SET
上面两种方法都有一个问题,会发现,都需要设置 key 过期。那么为什么要设置key过期呢?如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。于是乎我们需要给锁加一个过期时间以防不测。
但是借助 Expire 来设置就不是原子性操作了。所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。
11、Reids三种不同删除策略
定时删除:在设置键的过期时间的同时,创建一个定时任务,当键达到过期时间时,立即执行对键的删除操作
惰性删除:放任键过期不管,但在每次从键空间获取键时,都检查取得的键是否过期,如果过期的话,就删除该键,如果没有过期,就返回该键
定期删除:每隔一点时间,程序就对数据库进行一次检查,删除里面的过期键,至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
定时删除
**优点:**对内存友好,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期间所占用的内存
**缺点:**对cpu时间不友好,在过期键比较多时,删除任务会占用很大一部分cpu时间,在内存不紧张但cpu时间紧张的情况下,将cpu时间用在删除和当前任务无关的过期键上,影响服务器的响应时间和吞吐量
定期删除
由于定时删除会占用太多cpu时间,影响服务器的响应时间和吞吐量以及惰性删除浪费太多内存,有内存泄露的危险,所以出现一种整合和折中这两种策略的定期删除策略。
定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。
定时删除策略有效地减少了因为过期键带来的内存浪费。
惰性删除
**优点:**对cpu时间友好,在每次从键空间获取键时进行过期键检查并是否删除,删除目标也仅限当前处理的键,这个策略不会在其他无关的删除任务上花费任何cpu时间。
**缺点:**对内存不友好,过期键过期也可能不会被删除,导致所占的内存也不会释放。甚至可能会出现内存泄露的现象,当存在很多过期键,而这些过期键又没有被访问到,这会可能导致它们会一直保存在内存中,造成内存泄露。
12、Redis常见的几种缓存策略
Cache-Aside
Read-Through
Write-Through
Write-Behind
13 、Redis5 种基础数据结构原理(可通过rdb持久化查看https://www.jianshu.com/p/154aae2afcfc):
1、string (字符串)、
2、list (列表:): Redis 底层存储 LINKEDLIST(双向链表 )和ziplist(压缩列表,ziplist是存储在一段连续的内存上,存储效率高,但是它不利于修改操作,插入和删除数都很麻烦,复杂度高,而且其需要频繁的申请释放内存,特别是ziplist中数据较多的情况下,搬移内存数据太费,多通过配置来限制每个节点的元素个数:list-max-ziplist-size)来实现quicklist的。如果插入节点中的的ziplist大小没有超过限制(list-max-ziplist-size),那么直接调用ziplistPush函数压入;如果插入节点中的ziplist大小超过了限制,则新建一个quicklist节点(自然会创建一个新的ziplist),新的数据项会压入到新的ziplist,新的quicklist节点插入到原有的quicklist
3、set(集合):底层使用了intset(整数集合)或hashtable(使用字典实现的哈希对象)两种数据结构存储的,intset我们可以理解为数组(查找数据的时候是通过二分查找来实现的),使用intset存储必须满足下面两个条件,否则使用hashtable,条件如下:
结合对象保存的所有元素都是整数值
集合对象保存的元素数量不超过512个
4、hash (哈希):数组 + 链表二维结构,ZIPLIST或hashtable(使用字典实现的哈希对象)
5、 zset (有序集合):底层的存储结构包括ziplist或skiplist,在同时满足以下两个条件的时候使用ziplist,其他时候使用skiplist,两个条件如下:
有序集合保存的元素数量小于128个
有序集合保存的所有元素的长度小于64字节