what:
缓存穿透:key对应的数据在数据源并不存在,请求数据没有被缓存命中,直接到DB或者存储设备中查询,从而压垮下游的数据源。例如:一个服务缓存了手机号及对应手机信息,当请求是一个非法手机号时,那么每次请求缓存都会被穿透,从而失效。很多服务攻击也采用该种方式。
缓存击穿:key对应数据存在缓存中,但是由于数据过期,缓存采用的查询更新的机制。如果在过期的一瞬间,大量并发请求过来,这些请求都会请求下游的DB或者存储设备,从而压垮下游的数据源。
缓存雪崩:缓存重启(暂时数据不全)或者大量的数据在某个时间点失效,从而导致大量请求到DB或者存储设备,从而压垮下游的数据源。如下图:
注意:缓存击穿和缓存雪崩,核心区别:在于雪崩时针对很多key的缓存,击穿则是某一个key(热点的key)。
how:
缓存穿透:
1、使用布隆过滤器,将非法的请求直接过滤掉;
2、简单的方案:直接将不存在value的key对应的数据缓存个null,但是过期时间设置的相对短一些,例如:3分钟;
缓存击穿:
key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。
1、使用互斥锁(mutex):就是发现数据失效时,不直接从下游数据源查询,而是获得一个互斥锁,只有获得锁的请求才去查询数据,并更新;其他的就重试整个get缓存的方法,或者超时。
简单互斥锁,例如:SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
缓存雪崩:
1、采用加锁或者队列的方案,减轻对下游数据的并行访问量。
2、在缓存数据失效的时间后面,再加个随机数,从而减小大量数据同时失效的可能;
3、设置缓存过期标记和过期时间不同。例如:过期时间是过期标记时间的1倍,那么过期标记标记数据已经过期了(如果过期会触发,后台线程更新对应key的数据),实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。