什么是缓存穿透,以及解决方案?
解释
缓存穿透是指访问一个不存在的数据,缓存和数据库中都没有该数据,此时访问数据在缓存中查询不到会一直访问数据库,导致数据库的压力变大,甚至导致宕机。
原因
很可能是外部攻击导致,大量请求去访问一个不存在的数据,导致Redis的穿透。
解决方案
- 缓存空数据:当发现某个请求的数据在缓存和数据库中都不存在时,此时将返回一个空数据,并将空数据写入到缓存当中,当下一次访问该数据时缓存会直接返回空数据,避免再次访问数据库。
缺点:容易导致数据不一致、占用内存空间
- 布隆过滤器:是一个bit向量或bit数组,告诉某个数据一定不存在或可能存在,数据经过哈希函数(可能经过多个哈希函数得到多个值)得到哈希值,将对应数组的位置置为1,当访问某个数据时,若过滤器中所有哈希值的对应位置都为1,则可能存在该数据,继续往下查询,反之,拒绝该请求。
缺点:哈希函数容易导致哈希冲突,有一定的误判率。
- 哈希函数越多,位置置为1的速度就越快,反而提高误判率
- 数组越长,误判率越低,但增加了内存开销
- 元素越多,越容易误判
什么是缓存击穿,以及解决方案?
解释
缓存击穿是指某设置了过期时间的key,在某一个时间点过期的时候,此时有这个key的大量并发请求进来,发现缓存过期后会去数据库加载数据并保存到缓存,大量的并发请求可能把数据库压垮。
解决方案
- 逻辑过期:从过期时间入手,在设置key时,设置一个过期时间字段存入缓存中,不再给key设置过期时间。查询缓存时,若判断出来当前数据已经过期,则当前线程请求获得锁,开启另一个线程去重构数据,直到执行完释放锁,而当前线程返回后直接返回数据,其他线程也直接返回数据。
优点:高可用性、性能好
缺点:在重构完成前,返回的都是脏数据
- 互斥锁:当缓存失效时,当前线程去获得一个互斥锁,去数据库加载数据并写入缓存,当其他线程进来发现获取锁失败,则会休眠等待锁释放,重新执行当前逻辑。
优点:能够保证数据的强一致性
缺点:性能不高、可能产生死锁
什么是缓存雪崩,以及解决方案?
解释
缓存雪崩是指同一时间大量的Key过期或者Redis服务宕机,导致大量请求到达数据库,给数据库带来巨大压力。
解决方案
- 给不同key的TLL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
降级
解释
当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
策略
降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。
- 服务方式:可以拒接服务,可以延迟服务,也有时候可以随机服务。
- 服务范围:可以砍掉某个功能,也可以砍掉某些模块。
- 熔断:当系统检测到某个服务调用失败次数超过一定阈值时,自动触发熔断,暂停对该服务的调用。
限流
解释
对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机
策略
- 固定窗口(计数器):在指定周期内累加访问次数,当访问次数达到阙值后,会触发限流策略。不过会产生临界问题。
- 滑动窗口:将一个大窗口分为若干个小窗口,每个小窗口有独立的时间点和计数器,当请求的时间点大于当前窗口的最大时间点时,则将窗口向前平移一个小窗口,小窗口内的访问之和即为大窗口的访问次数,超过阈值会触发限流。
- 令牌桶限流:对于每一个请求都需要从令牌桶获得一个令牌。如果没有获得令牌则会触发限流,系统会以恒定速度往固定容量的令牌桶中放入令牌。令牌桶有固定的大小,如果令牌桶被填满,则会丢弃令牌。
- 漏桶限流:当流量超出桶的容量(固定)时,多的流量就会被丢弃。流量则一直按照稳定的速率流出,保证访问的平稳。一方面,流量的突发情况得到了控制,访问也比较稳定