一、缓存穿透问题
作为后端的开发人员,我们会遇到这样一个常见的缓存使用方式:读请求来了,先查下缓存,缓存值有值就命中,就直接返回;如果缓存没有命中,就去查询数据库,然后把数据库的值更新到缓存,再返回。
1、缓存穿透是什么?
缓存穿透: 指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。通俗点来讲,读请求访问时,缓存和数据库都没有这个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。
缓存穿透一般都是这几种情况产生的:
业务不合理的设计: 比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护。
业务、运维、开发失误的操作: 比如缓存和数据库的数据都被误删了。
非法请求攻击: 比如黑客故意捏造大量非法请求,以读取不存在的业务数据。
2、如何避免缓存穿透呢?
-
如果是非法请求,我们可以在API入口,对参数进行校验,过滤非法值。
-
如果查询数据库为空,我们可以给缓存设置个空值,或者默认值。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效)**
-
使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。**
3、布隆过滤器原理
布隆过滤器原理: 它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。
二、缓存雪崩问题
缓存雪崩: 指缓存中数据大批量到达过期时间,而查询数量巨大,请求都直接访问数据库,引起数据库压力过大甚至宕机。
- 缓存雪崩一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间,让过期时间相对离散一点。如采用一个较大的固定值+一个较小的随机值。例如:5小时+0-1800秒。
- Redis故障宕机也可能引起缓存雪崩,这里就需要构造redis高可用集群了。
三、缓存击穿
缓存击穿: 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到DataBase。
- 缓存击穿看着有点像缓存雪崩,其实他两区别就在于,缓存雪崩是指数据库压力过大甚至宕机,缓存击穿只是大量请求到了数据库层面。可以这样理解,击穿是雪崩的一个子集。也有一些文章这样说,区别在于击穿是针对于某一热点key,而雪崩则是大量key。
解决方案有两种:
- 1、使用互斥锁方案 。 缓存失效时,不是立即去加载DB数据库,而是先使用某些带成功返回的原子操作命令,(如Redis的setnx)去操作,成功的时候,再去加载DB数据库和设置缓存,否则就去重试获取缓存。
- 2、永不过期,是指没有设置过期时间,但是热点数据快要过期时,用一个异步线程去更新和设置过期时间。
四、什么是热key问题,如何解决热key问题?
1、什么是热key问题?
在redis中,我们把访问频率高的key,称为热点key。如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。
2、热点key是怎么产生的呢? 主要原因有两个:
-
用户消费的数据远大于生产的数据,如秒杀、热点新闻等读多写少的场景。
-
请求分片集中,超过单redis服务器的性能,比如固定名称key,hash落入同一台服务器,瞬间访问量极大,超过机器瓶颈,产生热点key问题。
3、那么在日常开发中,如何识别到热点key呢?
- 凭个人经验判断哪些是热点key
- 客户端统计上报
- 服务代理层上报
4、如何解决热可以问题?
- redis集群扩容:增加分片副本,均衡读流量。
- 将热key分散到不同的服务器。
- 使用二级缓存,即JVM本地缓存,减少redis的读请求。