缓存穿透、缓存雪崩和缓存击穿及其他小问题
1.说说你项目中redis的应用
? 一般使用redis做缓存,也可以使用redis做锁,有以下应用场景:
- 登录功能:在登录时,将sessionId或token存入到redis中,设置过期时间,用于登录验证
- 加锁:单体应用需要单体锁,分布式环境下需要分布式锁
- 缓存数据:在秒杀项目中,需要将商品数据存放在redis中,获取商品数据会更快
- 秒杀解决超卖问题:使用redis中increment原子性指令,可以解决超卖问题
2.redis是单线程还是多线程
- 无论什么版本,工作线程只有一个,只不过在6.x版本出现了IO多线程
- 单线程满足redis的串行原子,只不过IO多线程后,把输入/输出放到更多的线程里去并行
- 由于IO多线程,客户端被读取的顺序是不能保障的
- 在一个连接里的顺序是可以保障的
3.redis事务执行失败怎么办?
? redis中事务执行失败之后,不像mysql会回滚(rollback),redis执行成功的指令就成功,失败的指令就失败,不会回滚。
4.redis存在线程安全的问题吗?为什么?
? redis可以保障内部串行,外界使用的时候要自行保障,业务上要自行保障
5.什么是缓存穿透?怎么解决?
? 在高并发项目中一般使用redis做缓存,将数据放入redis中,请求进来之后直接从redis中获取数据,而不访问数据库,类似于下面这种架构:
5.1 什么是缓存穿透
? 可以从上面的架构图中知道,客户端每次访问数据的时候都会先在redis中进行访问,若redis中没有这个数据就会去数据库中访问。
? 若有一些恶意请求,专门请求一些参数格式不对的数据,则redis中没有会去数据库中进行查询,数据库中也没有。
? 当这样的请求大量出现时,那么请求就会直接打到数据库上,数据库就很容易宕机,这就是缓存穿透。
5.2 解决缓存穿透
解决方式1:校验参数
? 对请求的参数进行校验,若出现一些不符合条件的参数直接返回请求,不会让其查询缓存和数据库
解决方式2:返回空字符串并存入redis
? 当在redis中无法查到时,这时去数据库进行查询,若也是空,那么也将此key存入redis中,value为空字符串即可。
解决方式3:布隆过滤器
? 使用布隆过滤器对所有的key进行保存,若查不到此数据,那肯定是没有,直接返回。
5.4 如何处理并发量大时一瞬间访问数据库?
为什么会产生这个问题?
? 虽然为了解决缓存穿透有那么多方案,但是缓存穿透也会有一瞬间进入数据库中的,哪怕这一瞬间很短,当并发量非常大时,这一瞬间的请求也会非常多,这就造成了数据库可能就因为这一瞬间的压力而崩溃。
? 这个问题不但在缓存穿透中存在,也在缓存击穿和缓存雪崩中存在,只要是有大量的请求访问,并且只要是会进入的数据库,那么都要解决这个问题。
解决这个问题
? 为了解决这个问题,我们需要使用锁,当在redis中查询不到数据时就要去数据库查找,在去数据库查找之前设置一把锁,每次只允许一个请求进去,在数据库中就算查不到,那也会在redis中进行空值缓存,后面的请求就直接在redis中进行查询。
6.什么是缓存击穿?怎么解决?
6.1 什么是缓存击穿
? 在高并发环境下,一个热点key过期(或一个没有被缓存过的数据),这时大量的并发请求突然过来,redis中查不到数据,那么就会去数据库进行查询,大量请求可能就会使数据库宕机,这就是缓存击穿。
6.2 解决缓存击穿(加锁)
? 因为缓存击穿访问的数据在数据库中是存在的,所以设置一把锁,当一个线程抢到锁,其他没有抢到锁的线程睡眠(sleep),抢到锁的线程将查询的数据回写入redis中,其他线程在redis中可以查到数据之后,直接返回。
? 以下是执行的顺序:
- 线程加锁
- 所有线程都来抢锁
- 抢到锁的线程访问数据库
- 查询到数据之后将数据回写到redis中
- 睡眠的线程重新回到第二步,重新查询redis
7.什么是缓存雪崩?怎么解决?
7.1 什么是缓存雪崩
? 当请求的数据大量同时过期(或没有被缓存)时,请求就回去数据库进行查询,将查询出来的数据重新写入redis。
7.2如何解决
不同的key设置不同的过期时间
? 缓存雪崩是因为大量的key同时过期,那么就可以给每个key设置不同的过期时间(随机的过期时间)
设置热点数据的key永不过期(简单粗暴)
? 若将热点数据的key设置为永不过期,那就直接从根源上避免的缓存雪崩的问题
|