## 问题现象 Redis中很容易出现的三大问题现象:缓存击穿、缓存穿透以及缓存雪崩。 **缓存击穿** 请求是如何取到数据的:当接收到用户请求,首先先尝试从Redis缓存中获取到数据,如果缓存中能取到数据则直接返回结果,当缓存中不存在数据时从DB获取数据,如果数据库成功取到数据,则更新Redis,然后返回数据,如果DB无数据,则返回空结果。那什么情况下会出现三大问题现象呢?我们先来看下缓存击穿的情况: **定义:**高并发的情况下,某个热门key突然过期,导致大量请求在Redis未找到缓存数据,进而全部去访问DB请求数据,引起DB压力瞬间增大。 **解决方案:**缓存击穿的情况下一般不容易造成DB的宕机,只是会造成对DB的周期性压力。对缓存击穿的解决方案一般可以这样:Redis中的数据不设置过期时间,然后在缓存的对象上添加一个属性标识过期时间,每次获取到数据时,校验对象中的过期时间属性,如果数据即将过期,则异步发起一个线程主动更新缓存中的数据。但是这种方案可能会导致有些请求会拿到过期的值,就得看业务能否可以接受,如果要求数据必须是新数据,则最好的方案则为热点数据设置为永不过期,然后加一个互斥锁保证缓存的单线程写。 **缓存穿透** **定义:**缓存穿透是指查询缓存和DB中都不存在的数据。比如通过id查询商品信息,id一般大于0,攻击者会故意传id为-1去查询,由于缓存是不命中则从DB中获取数据,这将会导致每次缓存都不命中数据导致每个请求都访问DB,造成缓存穿透。 **解决方案:**缓存穿透的解决方案可以分成两个部分:首先在API层增加基本校验:用户鉴权校验,id校验。比如用户鉴权失败或者id < 0的请求直接进行拦截。其次在缓存和DB都取不到数据的时候将将key-value存储成key-null存储到Redis, 过期时间可以存储的短点比如60S,防止短时间内攻击者不断发起请求导致数据库压力过大出现宕机。 **缓存雪崩** **定义:**缓存中如果大量缓存在一段时间内集中过期了,这时候会发生大量的缓存击穿现象,所有的请求都落在了DB上,由于查询数据量巨大,引起DB压力过大甚至导致DB宕机。 **解决方案:**缓存雪崩一般没有完美解决的方法,但是我们可以尽量分析用户行为,尽量保证key的失效时间比较平均,防止同一时间出现大量缓存数据同时过期的现象,并且设置热点数据永不过期。同时如果为分布式环境下,使用分布式锁来保证缓存的单线程写,这样可以避免同一时间大量缓存失效导致请求全部落在DB上。而我觉得如果可以接受有些请求拿到过期值,最合理的方案实际上就是使用缓存击穿的方案:Redis中的数据不设置过期时间,然后在缓存的对象上添加一个属性标识过期时间,每次获取到数据时,校验对象中的过期时间属性,如果数据即将过期,则异步发起一个线程主动更新缓存中的数据。