简单记录了一些关于缓存击穿、雪崩、穿透的概念及解决方案。
缓存击穿
概念
缓存击穿是指查询一个不存在的数据,由于缓存没有命中,所以每次都需要去数据库中查询,查不到数据则不写入缓存。这样将导致每次都需要去数据库中查询数据,如果请求量多的话,会给数据库带来很大压力。
通俗的说,就是读请求访问时,缓存和数据库都某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。
处理方法
- 对于非法请求,可以在API入口,对参数进行校验,过滤非法值。
- 如果查询数据库为空,可以给缓存设置一个空值,或者默认值。如果有写请求进来的话,需要更新缓存,以保持数据一致性。同时,最后给缓存设置适当的过期时间。
- 使用布隆过滤器——当一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。
关于布隆过滤器,它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。
缓存雪崩
概念
指的是缓存在某个时间点大量失效,此时查询量巨大,缓存失效使得全部请求都打到了数据库中,导致数据库压力过大甚至宕机。
解决方法
既然缓存雪崩的原因是缓存在某个时间点大量失效,那么让这个时间分布离散一些即可避免。比如,可以采用一个较大的固定值+一个较小的随机值。 除此之外,Redis集群故障也可能导致缓存雪崩,这就需要构造Redis高可用集群了。
缓存击穿
概念
缓存击穿,就是指在处理查询操作时,某个热点key突然过期,而此时对这个key有大量的并发请求,大量的请求都打到了数据库中。
与缓存雪崩有些类似,但二者的区别是,缓存雪崩是指数据库压力过大甚至宕机,缓存击穿仅仅只是大量并发请求到了DB数据库层面。可以理解为击穿是雪崩的一个子集。击穿是一个key失效,雪崩是key大面积失效。
解决方法
- 使用互斥锁,缓存失效时,不是立即去加载db数据,而是先使用某些带有成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。
- 永不过时,不设置过期时间,在热点数据要过期时,异步线程去更新和设置过期时间。
|