目录
- Redis 面试题汇总
- 1. MySQL 里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
- 1.1 Redis提供了8种策略
- 1.2 最大内存设置
- 2. 为什么说 redis 能够快速执行
- 3. Redis中的五种数据结构
- 3.1 string 字符串类型
- 3.2 list 列表
- 3.3 hash 类型
- 3.4 set 无序集合
- 3.5 set 有序
- 4. Redis 的持久化
- 4.1 Redis 的持久化机制
- 4.2 Redis 持久化方案
- 4.3 Redis 持久化方案的优缺点
- 5. 缓存穿透、缓存击穿、缓存雪崩解决方案
- 5.1 缓存穿透
- 5.2 缓存击穿
- 5.3 缓存雪崩
- 6. 使用过Redis分布式锁么,它是什么回事?
- 7. 内存淘汰机制
- 8. Redis 和 Mysql 的数据不一致怎么办
- 9. Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
- 10. 项目中有没有用Redis事务
- 11. Redis主要消耗什么物理资源?
- 12. Redis的内存用完了会发生什么?
- 13. 说说 Redis 哈希槽的概念?
- 14. Redis 集群最大节点个数是多少?
- 15. Redis 集群如何选择数据库?
- 16. 怎么测试 Redis 的连通性?
- 17. 如果有大量的 key 需要设置同一时间过期,一般需要注意什么?
Redis 面试题汇总
1. MySQL 里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
这个问题主要考察了以下几点内容:
1.Redis的内存淘汰策略。
2.Redis的最大内存设置。
1.1 Redis提供了8种策略
(1)volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
(2)volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
(3)volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
(4)volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
(5)allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
(6)allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
(7)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
(8) no-enviction(驱逐):禁止驱逐数据,这也是默认策略。意思是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失。
这八种大体上可以分为4中,lru、lfu、random、ttl。
1.2 最大内存设置
同样是在redis.conf配置文件中,可以对最大内存进行设置,单位为bytes:当使用的内存到达指定的限制时,Redis会根据内存淘汰策略删除键,以释放空间。
2. 为什么说 redis 能够快速执行
① 绝大部分请求是纯粹的内存操作(非常快速)
② 采用单线程,避免了不必要的上下文切换和竞争条件
③ 非阻塞IO - IO多路复用
3. Redis中的五种数据结构
3.1 string 字符串类型
String 类型是二进制安全的,即可以存储任何数据、比如数字、图片、序列化对象等。
## get,mget
127.0.0.1:6379> MSET key1 "hello" key2 "world" #批量设置key1和key2两个键
OK
127.0.0.1:6379> keys *
1) "key1"
2) "key2"
127.0.0.1:6379> mget key1 key2 #批量获取
1) "hello"
2) "world"
3.2 list 列表
列表的元素类型为 string,按照插入顺序排序,在列表的头部或尾部添加元素
## lrange,lindex
127.0.0.1:6379> LRANGE key 0 2 #取从位置0开始到位置2结束的3个元素
1) "d"
2) "c"
3) "b"
127.0.0.1:6379> LRANGE key 0 -1 #取链表中的全部元素,-1表示最后一个元素
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> LRANGE mykey 0 -1
1) "c"
2) "a"
3) "d"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> LINDEX mykey 1 #获取索引值为1(头部的第二个元素)的元素值
"a"
127.0.0.1:6379> LINDEX mykey 6 #超出范围返回nil
(nil)
3.3 hash 类型
hash 用于存储对象
## hget,hmget,hgetall,hkeys,hvals
127.0.0.1:6379> HSET myhash name "lisi" #给键值为myhash的键设置字段为name,值为lisi
127.0.0.1:6379> HGET myhash name #获取键值myhash的字段name的值
"lisi"
127.0.0.1:6379> HMSET myhash name1 "zhangsan" name2 "lisi" #一次性设置多个字段
OK
127.0.0.1:6379> HMGET myhash name1 name2 #获取多个字段
1) "zhangsan"
2) "lisi"
127.0.0.1:6379> HGETALL myhash #获取所有字段和值
1) "name1"
2) "zhangsan"
3) "name2"
4) "lisi"
127.0.0.1:6379> HKEYS myhash #获取myhash键中所有字段的名字
1) "name1"
2) "name2"
127.0.0.1:6379> HVALS myhash #获取myhash键中所有的值
1) "zhangsan"
2) "lisi"
3.4 set 无序集合
无序集合,元素类型为String类型,元素具有唯一性,不允许存在重复的成员。
## smembers
127.0.0.1:6379> SADD myset a b c d
(integer) 4
127.0.0.1:6379> SMEMBERS myset #查看插入的结果
1) "e"
2) "c"
3) "b"
4) "d"
5) "a"
127.0.0.1:6379> SCARD myset #获取set几核中的元素的数量
(integer) 5
3.5 set 有序
有序集合,元素类型为Sting,元素具有唯一性,不能重复。每个元素都会关联一个double类型的分数score(表示权重),可以通过权重的大小排序,元素的score可以相同。
## zrange
127.0.0.1:6379> ZADD score 1 "zhangsan" #添加一个分数为1的成员zhangsan
(integer) 1
127.0.0.1:6379> ZADD score 2 "lisi" 3 "wangwu" #添加两个分数分别是2和3的lisi,wangwu的成员
(integer) 2
127.0.0.1:6379> ZRANGE score 0 -1
1) "zhangsan"
2) "lisi"
3) "wangwu"
127.0.0.1:6379> ZRANGE score 0 -1 WITHSCORES #0表示第一个成员,-1表示最后一个成员。WITHSCORES选项表示返回的结果中包含每个成员及其分数,否则只返回成员。
1) "zhangsan"
2) "1"
3) "lisi"
4) "2"
5) "wangwu"
6) "3"
4. Redis 的持久化
4.1 Redis 的持久化机制
- RDB持久化
RDB持久化即通过创建快照(压缩的二进制文件)的方式进行持久化,保存某个时间点的全量数据。RDB持久化是Redis默认的持久化方式。RDB持久化的触发包括手动触发与自动触发两种方式。
- AOF持久化
AOF(Append-Only-File)持久化即记录所有变更数据库状态的指令,以append的形式追加保存到AOF文件中。在服务器下次启动时,就可以通过载入和执行AOF文件中保存的命令,来还原服务器关闭前的数据库状态。
- RDB、AOF混合持久化
Redis从4.0版开始支持RDB与AOF的混合持久化方案。首先由RDB定期完成内存快照的备份,然后再由AOF完成两次RDB之间的数据备份,由这两部分共同构成持久化文件。该方案的优点是充分利用了RDB加载快、备份文件小及AOF尽可能不丢数据的特性。缺点是兼容性差,一旦开启了混合持久化,在4.0之前的版本都不识别该持久化文件,同时由于前部分是RDB格式,阅读性较低。
4.2 Redis 持久化方案
- 如果Redis只是用来做缓存服务器,比如数据库查询数据后缓存,那可以不用考虑持久化,因为缓存服务失效还能再从数据库获取恢复。
- 如果你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。如果你可以接受灾难带来的几分钟的数据丢失,那么可以仅使用RDB。
通常的设计思路是利用主从复制机制来弥补持久化时性能上的影响。
即Master上RDB、AOF都不做,保证Master的读写性能,而Slave上则同时开启RDB和AOF(或4.0以上版本的混合持久化方式)来进行持久化,保证数据的安全性。
4.3 Redis 持久化方案的优缺点
- RDB持久化
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。
- AOF持久化
与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。
5. 缓存穿透、缓存击穿、缓存雪崩解决方案
5.1 缓存穿透
① 查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短
② 使用布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
5.2 缓存击穿
① 使用互斥锁:当缓存失效时,不立即去 load db,先使用如 Redis 的 setnx 去设置一个互斥锁,当操作成功返回时再进行 load db 的操作并回设缓存,否则重试 get 缓存的方法。
② 设置永远不过期:物理不过期,但逻辑过期(后台异步线程去刷新)。
5.3 缓存雪崩
将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
6. 使用过Redis分布式锁么,它是什么回事?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。
这时候对方会告诉你说你回答得不错,然后接着问如果在 setnx 之后执行 expire之前进程意外 crash 或者要重启维护了,那会怎么样?这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:
我记得 set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和expire 合成一条指令来用的!
7. 内存淘汰机制
redis 内存淘汰机制有以下几个:
noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。
8. Redis 和 Mysql 的数据不一致怎么办
采用延时双删策略
- 第一个删redis。如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。
- 第二个删redis。如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
- 先淘汰缓存
- 再写数据库(这两步和原来一样)
- 休眠800ms,再次淘汰缓存
这么做,可以将800ms内所造成的缓存脏数据,再次删除。
9. Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
使用keys指令可以扫出指定模式的key列表。
对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的。
keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
10. 项目中有没有用Redis事务
采用的是Redis Cluster集群架构,不同的key是有可能分配在不同的Redis节点上的,在这种情况下Redis的事务机制是不生效的。其次,Redis事务不支持回滚操作,所以基本不用!
11. Redis主要消耗什么物理资源?
内存
12. Redis的内存用完了会发生什么?
如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。
13. 说说 Redis 哈希槽的概念?
答:Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
14. Redis 集群最大节点个数是多少?
16384 个。
15. Redis 集群如何选择数据库?
Redis 集群目前无法做数据库选择,默认在 0 数据库
16. 怎么测试 Redis 的连通性?
ping
17. 如果有大量的 key 需要设置同一时间过期,一般需要注意什么?
如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。