最近在准备面试,决定先从redis开始,目前的方式是通过看视频和博客来巩固旧知识,并学习新知识。
本来是想用markdown来记录笔记,但发现对于复习而言,在看一个知识点的时候,会看到写在下面的答案或知识点。因此我这次使用了思维导图软件xmind来进行记录,目的只是为了方便自己复习,因为可以将知识点一个一个展开,展开前还可以在脑子里思考一下,尝试回答什么的。
个人比较少使用xmind,因此记录的并不是很好,但个人使用应该是足够了,文章只是为了记录一下学习历程。
redis使用场景问题
在了解这三个redis使用问题之前,需要先知道,请求访问数据A的流程:检查数据A是否缓存在redis中:
- 如果数据A缓存在redis中,返回已缓存数据
- 如果数据A未缓存在redis中,数据库查询数据A,查询数据A后,缓存到redis中,再返回给前端
缓存穿透
缓存穿透是指,某请求访问不存在的数据A,数据A本身不存在MySQL中,那redis缓存中也肯定不会存在,那么请求会穿透到MySQL中。
假设有大量请求访问不存在的数据,会造成大量的请求落到数据库上,数据库本身能承受的QPS有限,有导致数据库崩溃的风险。
解决办法
那么有什么解决办法呢?有两种。
- redis缓存空值
我们知道当查询MySQL数据库不存在的数据是会返回null的,因此只要对该请求对应的key来缓存为null就可以了。
这种办法简单有效,但对redis内存压力较大。 - 布隆过滤器
redis启动时,将MySQL会用在redis中的热点数据,存到布隆过滤器中。
布隆过滤器本质上是一个位图,其中只会存0和1,因此占用空间较小。布隆过滤器的原理是对数据的key进行三次不同的hash,得到三个下标,位图中这三个下标就会被设置为1。
此时如果使用key查询redis,经过布隆过滤器,三次hash,对应下标值都为1,就是可能存在该数据(这时候再会去redis或MySQL查询数据)否则直接返回空。
布隆过滤器有误判几率,判断为存在会误判,但判断不存在是一定正确的。
缓存击穿
缓存击穿是某个key设置了过期时间,在过期后,有大量请求同时访问该数据,由于从数据库查出数据并缓存到redis需要时间(可能是几ms)。但如果请求量过大,这些请求都落到了数据库中,有崩溃的风险。
解决方法
- 互斥锁
请求在访问该key时,加互斥锁,在得到结果并缓存到redis之前,都不允许其他请求访问该数据。
这种方式性能低,但保证了数据是最新的 - 逻辑过期时间
这种方式是在value中记录过期时间,实际上不会过期,只是在访问时判断该key的过期时间是否超过当前时间,如果过期了,会另开新线程,,然后返回旧值,而新线程会锁住该key,并到数据库更新最新值。
这种方式不保证数据最新,适合业务能够容忍几秒的非实时数据。
缓存雪崩
大量热点key同时失效,或者redis突然宕机,如同雪崩一样,导致大量请求落在数据库上。
解决方法
- 随机过期时间
只要给过期时间再加上一个的随机数即可,这样可以避免同时过期 - 部署redis集群
部署redis集群可以保证高可用,master宕机,slave上位继续运行 - 服务限流和降级
这方面了解较少,限流就是进行流量限制,每次最多只允许特定个数的请求,后面的需要排队。
降级就是丢弃无法处理的的请求,只处理一定数量范围的请求,来减轻服务器的压力。 - 多级缓存
使用本地缓存Guava或Caffeine来作为一级缓存,redis作为二级缓存