在使用缓存时,要注意:
- 缓存数据是有原始数据来源的,且允许丢失。数据丢失后,我们要从原始数据重新加载,不能认为缓存是绝对可靠的,也不能认为缓存不会删除没有过期的数据
- 缓存系统可以保存的数据量一定是小于原始数据的,我们应该根据数据特点,明确redis应该以怎样的算法来驱逐数据
常用的数据淘汰策略有:
allkeys-lru,针对所有 Key,优先删除最近最少使用的 Key;==
volatile-lru,针对带有过期时间的 Key,优先删除最近最少使用的 Key;
volatile-ttl,针对带有过期时间的 Key,优先删除即将过期的 Key(根据 TTL 的值);
allkeys-lfu(Redis 4.0 以上),针对所有 Key,优先删除最少使用的 Key;
volatile-lfu(Redis 4.0 以上),针对带有过期时间的 Key,优先删除最少使用的 Key。
缓存雪崩
由于缓存系统的 IOPS 比数据库高很多,因此要特别小心短时间内大量缓存失效的情况。这种情况一旦发生,可能就会在瞬间有大量的数据需要回源到数据库查询,对数据库造成极大的压力,极限情况下甚至导致后端数据库直接崩溃。这就是我们常说的缓存失效,也叫作缓存雪崩。
产生缓存雪崩的两个原因:
- 缓存系统本身不可用,导致大量请求直接回源到数据库
- 应用设计层面大量的key在同一时间过期,导致大量请求直接回源到数据库
第二个原因,在设计缓存时要确保大量的key不在同一时间过期,有两种方式:
- 差异化缓存过期时间
- 让缓存不主动过期,然后定时把所有数据更新到缓存,但是这种方法需要有回源的逻辑,我们没办法保证缓存中的数据永不丢失;
这两种方式都需要在吧数据从数据库加入缓存时,判断来自数据库的数据是否合法,比如最基本的空判断
缓存击穿
某些热点key在并发量很大的情况下,如果这个key过期,可能在某个瞬间出现大量并发请求同时回源,也就是大量的并发请求直接打到数据库;
这种情况下,可以考虑使用锁限制回源的并发;
缓存穿透
当缓存中没有数据时,不一定代表数据没有缓存,而是有可能数据压根不存在。如果大量请求查询了一个不存在的数据,会对数据库造成很大的性能压力
它和缓存击穿的差别是:缓存穿透是缓存没有起到压力缓冲的作用,而缓存击穿是指缓存失效瞬间大量的请求直接到达数据库
解决缓存穿透有两种方案:
- 对于不存在的数据,同样记录到缓存中,设置一个特殊值
- 使用 布隆过滤器1 做前置过滤,可以把所有可能的值保存在布隆过滤器中,从缓存读取数据前先过滤一次:
如果布隆过滤器认为值不存在,那么值一定是不存在的,无需查询缓存也无需查询数据库;
对于极小概率的误判请求,才会最终让非法 Key 的请求走到缓存或数据库。