上篇文章谈到了Redis分布式锁,实际上就是为了解释为什么做缓存采用Redis而不使用map/guava。缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map /guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 JVM 的销毁而结束。而且在多实例状态下缓存不具有唯一性。使用 Redis 作缓存称为分布式缓存,在多实例状态下共用一份缓存数据,缓存具有一致性。所以说在分布式下最合适的缓存方案就是采用Redis实现分布式缓存。
本篇文章主要谈谈Redis中很容易出现的三大问题现象:缓存击穿、缓存穿透以及缓存雪崩。不过在介绍这三个问题现象之前,我们首先需要先来了解下Redis中key的过期淘汰机制。众所周知,Redis可以对存储在Redis中的缓存数据设置过期时间,比如我们获取的短信验证码一般十分钟过期,我们这时候就需要在验证码存进Redis时添加一个key的过期时间,但是这里有一个需要格外注意的问题就是:并非key过期时间到了就一定会被Redis给删除。那么Redis是如何做到对过期key进行删除呢?Redis中对于过期key的删除分为两种策略:定期删除和惰性删除。
但是如果仅仅使用定期删除 + 惰性删除机制还是会留下一个严重的隐患:如果定期删除留下了很多已经过期的key,而且用户长时间都没有使用过这些过期key,导致过期key无法被惰性删除,从而导致过期key一直堆积在内存里,最终造成Redis内存块被消耗殆尽。那这个问题如何解决呢?这个时候Redis内存淘汰机制应运而生了。Redis内存淘汰机制提供了6种数据淘汰策略:
一般情况下,推荐使用volatile-lru策略,对于配置信息等重要数据,不应该设置过期时间,这样Redis就永远不会淘汰这些重要数据。对于一般数据可以添加一个缓存时间,当数据失效则请求会从DB中获取并重新存入Redis中。
缓存击穿
讲完了Redis的key的过期淘汰机制,接下我们可以进入正题:为什么会出现缓存击穿、缓存穿透和缓存雪崩现象呢?首先我们来看下请求是如何取到数据的:当接收到用户请求,首先先尝试从Redis缓存中获取到数据,如果缓存中能取到数据则直接返回结果,当缓存中不存在数据时从DB获取数据,如果数据库成功取到数据,则更新Redis,然后返回数据,如果DB无数据,则返回空结果。那什么情况下会出现三大问题现象呢?我们先来看下缓存击穿的情况:
缓存穿透
缓存雪崩