文章插图
本篇文章主要谈谈redis中很容易出现的三大问题现象:缓存击穿、缓存穿透以及缓存雪崩 。不过在介绍这三个问题现象之前,我们首先需要先来了解下Redis中key的过期淘汰机制 。众所周知,Redis可以对存储在Redis中的缓存数据设置过期时间,比如我们获取的短信验证码一般十分钟过期,我们这时候就需要在验证码存进Redis时添加一个key的过期时间,但是这里有一个需要格外注意的问题就是:并非key过期时间到了就一定会被Redis给删除 。那么Redis是如何做到对过期key进行删除呢?Redis中对于过期key的删除分为两种策略:定期删除和惰性删除 。
- 定期删除:Redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 Key,检查其是否过期,如果过期就删除 。为什么是随机抽取而不是检查所有key?因为你如果设置的key成千上万,每100毫秒都将所有存在的key检查一遍,会给CPU带来比较大的压力 。
- 惰性删除 :定期删除由于是随机抽取可能会导致很多过期 Key 到了过期时间并没有被删除 。所以用户在从缓存获取数据的时候,redis会检查这个key是否过期了,如果过期就删除这个key 。这时候就会在查询的时候将过期key从缓存中清除 。
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰 。
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰 。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰 。
- allkeys-lru:当内存不足以容纳新写入数据时移除最近最少使用的key 。
- allkeys-random:从数据集中任意选择数据淘汰 。
- no-enviction:当内存不足以容纳新写入数据时,新写入操作会报错 。
缓存击穿
讲完了Redis的key的过期淘汰机制,接下我们可以进入正题:为什么会出现缓存击穿、缓存穿透和缓存雪崩现象呢?首先我们来看下请求是如何取到数据的:当接收到用户请求,首先先尝试从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,防止短时间内攻击者不断发起请求导致数据库压力过大出现宕机 。
推荐阅读
- Redis键管理
- Redis:从认识安装到实现CURD
- php结合Redis实现投票项目并实时查看到投票情况
- 阿里云的redis规范
- Redis原理分享,从使用到会用
- Redis布隆过滤器
- 微服务架构中缓存模式
- Redis哈希类型
- 你知道 Redis数据结构底层实现吗?一文详解,彻底弄懂
- redis实现网关限流