1、在项目中缓存是如何使用的?为什么要用缓存?缓存使用不当会造成什么后果?
面试官心理分析
这个问题,互联网公司必问,要是一个人连缓存都不太清楚,那确实比较尴尬。
只要问到缓存,上来第一个问题,肯定是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用
了以后可能会有什么不良的后果?
这就是看看你对缓存这个东西背后有没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解
答,那面试官对你印象肯定不太好,觉得你平时思考太少,就知道干活儿。
面试题剖析
项目中缓存是如何使用的?
这个,需要结合自己项目的业务来。
为什么要用缓存?
用缓存,主要有两个用途:高性能、高并发。
高性能
假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作
mysql
,半天查出来一个
结果,耗时
600ms
。但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用
户。那么此时咋办?
缓存啊,折腾
600ms
查出来的结果,扔缓存里,一个
key
对应一个
value
,下次再有人查,别走
mysql
折腾
600ms
了,直接从缓存里,通过一个
key
查出来一个
value
,
2ms
搞定。性能提升
300
倍。
就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直
接将查询出来的结果放在缓存中,后面直接读缓存就好。
高并发
所以要是你有个系统,高峰期一秒钟过来的请求有
1
万,那一个
mysql
单机绝对会死掉。你这个时候就
只能上缓存,把很多数据放缓存,别放
mysql
。缓存功能简单,说白了就是
key-value
式操作,单机支撑
的并发量轻松一秒几万十几万,支撑高并发
so easy
。单机承载并发量是
mysql
单机的几十倍。
缓存是走内存的,内存天然就支撑高并发。
用了缓存之后会有什么不良后果?
常见的缓存问题有以下几个:
缓存与数据库双写不一致 、缓存雪崩、缓存穿透、缓存并发竞争后面再详细说明。
2、redis 都有哪些数据类型?分别在哪些场景下使用比较合适?
面试官心理分析
除非是面试官感觉看你简历,是工作
3
年以内的比较初级的同学,可能对技术没有很深入的研究,面试 官才会问这类问题。否则,在宝贵的面试时间里,面试官实在不想多问。
其实问这个问题,主要有两个原因:
看看你到底有没有全面的了解
redis
有哪些功能,一般怎么来用,啥场景用什么,就怕你别就会最
简单的
KV
操作;
看看你在实际项目里都怎么玩儿过
redis
。
要是你回答的不好,没说出几种数据类型,也没说什么场景,你完了,面试官对你印象肯定不好,觉得你平时就是做个简单的 set
和
get
。
面试题剖析
redis 主要有以下几种数据类型:
string
hash
list
set
Zset
(
sorted set
)
string
这是最简单的类型,就是普通的
set
和
get
,做简单的
KV
缓存。
hash
这个是类似
map
的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在 redis
里,然后每次读写缓存的时候,可以就操作
hash
里的某个字段。
list
list
是有序列表,这个可以玩儿出很多花样。
比如可以通过
list
存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西。
比如可以通过
lrange
命令,读取某个闭区间内的元素,可以基于
list
实现分页查询,这个是很棒的一个 功能,基于 redis
实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页 一页走。
hset person name bingohset person age 20hset person id 1 hget person nameperson = {
"name": "bingo", "age": 20, "id": 1}
# 0
开始位置,
-1
结束位置,结束位置为
-1
时,表示列表的最后一个位置,即查看所有。
lrange mylist 0 -1
比如可以搞个简单的消息队列,从
list
头怼进去,从
list
尾巴那里弄出来。
set
set
是无序集合,自动去重。
直接基于
set
将系统里需要去重的数据扔进去,自动就给去重了,如果你需要对一些数据进行快速的全 局去重,你当然也可以基于 jvm
内存里的
HashSet
进行去重,但是如果你的某个系统部署在多台机器上 呢?
得基于
redis
进行全局的
set
去重。
sorted set
sorted set
是排序的
set
,去重但可以排序,写进去的时候给一个分数,自动根据分数排序。
3、redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?
面试官心理分析
如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当然的认为写进 redis的数据就一定会存在,后面导致系统各种
bug
,谁来负责?
常见的有两个问题:
(1)往 redis 写入的数据怎么没了?
可能有同学会遇到,在生产环境的
redis
经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 redis
你就没用对啊。
redis
是缓存,你给当存储了是吧?
啥叫缓存?用内存当缓存。内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。 可能一台机器就几十个 G
的内存,但是可以有几个
T
的硬盘空间。
redis
主要是基于内存来进行高性 能、高并发的读写操作的。
那既然内存是有限的,比如
redis
就只能用
10G
,你要是往里面写了
20G
的数据,会咋办?当然会干掉10G 的数据,然后就保留
10G
的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据, 保留常用的数据了。
(2)数据明明过期了,怎么还占用着内存?
这是由
redis
的过期策略来决定。
面试题剖析
redis 过期策略
redis 过期策略是:定期删除+惰性删除。
所谓定期删除,指的是
redis
默认是每隔
100ms
就随机抽取一些设置了过期时间的
key
,检查其是否过期,如果过期就删除。
假设
redis
里放了
10w
个
key
,都设置了过期时间,你每隔几百毫秒,就检查
10w
个
key
,那
redis
基本上就死了,cpu
负载会很高的,消耗在你的检查过期
key
上了。注意,这里可不是每隔
100ms
就遍历所有的设置过期时间的 key
,那样就是一场性能上的灾难。实际上
redis
是每
100ms
随机抽取一些
key
来检查和删除的。
但是问题是,定期删除可能会导致很多过期
key
到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个 key
的时候,
redis
会检查一下 ,这个
key
如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
获取
key
的时候,如果此时
key
已经过期,就删除,不会返回任何东西。
答案是:走内存淘汰机制。
内存淘汰机制
redis
内存淘汰机制有以下几个:
- noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key 优先移除。