目录

Redis基础


缓存击穿

定义:缓存击穿(Cache Breakdown)是指在高并发访问某个缓存中的数据时,该数据刚好失效(缓存过期),导致大量请求直接打到数据库。

原因:发生在缓存过期的瞬间,因为并发访问很高,缓存失效后没有及时更新,导致大量请求直接访问数据库。

解决方案

  1. 互斥锁(Mutex):在访问缓存时,如果发现缓存失效,使用互斥锁(如 Redis 的分布式锁)来确保只有一个线程能去加载数据并更新缓存,其他线程等待。
  2. 提前更新缓存:在缓存即将失效时,提前更新缓存数据,防止在高并发情况下出现击穿问题。

缓存穿透

定义:缓存穿透(Cache Penetration)是指大量请求的数据根本不存在于缓存和数据库中,导致所有请求直接打到数据库。

原因:由于恶意攻击或查询的数据本身不存在,从而绕过缓存层,直接访问数据库。

解决方案

  1. 缓存空值:对于数据库中不存在的查询结果,缓存一个空值(null),并设置一个较短的过期时间。
  2. 布隆过滤器:在查询缓存前,通过布隆过滤器(Bloom Filter)快速判断数据是否存在,如果不存在则直接返回,避免访问数据库。

缓存雪崩

定义:缓存雪崩(Cache Avalanche)是指在同一时间大量缓存集中失效,导致大量请求直接打到数据库,可能导致数据库崩溃。

原因:主要是因为缓存集中设置了相同的过期时间,导致在某一时刻大量缓存同时失效。

解决方案

  1. 缓存过期时间随机化:在设置缓存时,给每个缓存设置一个随机的过期时间,避免集中失效。
  2. 分布式缓存:使用分布式缓存系统,分散缓存存储,避免单点集中失效。
  3. 二级缓存:在缓存失效后,通过二级缓存(例如本地缓存)来缓解数据库压力。

内存淘汰策略

Redis 在内存达到上限时,会根据内存淘汰策略决定如何释放内存:

  1. noeviction:默认策略,不淘汰,并不再允许写操作
  2. allkeys-lru:从所有键中使用 LRU 算法淘汰
  3. volatile-lru:从设置了过期时间的键中使用 LRU 算法淘汰
  4. allkeys-random:从所有键中随机淘汰
  5. volatile-random:从设置了过期时间的键中随机淘汰
  6. volatile-ttl:从设置了过期时间的键中,优先淘汰 TTL 较短的键
  7. volatile-lfu:从所有键中使用 LFU 算法淘汰
  8. allkeys-lfu:从设置了过期时间的键中使用 LFU 算法淘汰

LRU

LRU(Least Recently Used)最近最少使用算法,淘汰规则基于访问时间,淘汰最久未使用的元素。

LRU 通常双向链表 + 哈希表实现,但对 Redis 来说内存开销太大。

近似 LRU 策略

Redis 中使用了一种基于采样的近似 LRU 算法:

  1. 在 Dict 中维护每个 key 的上次访问时间;
  2. 进行内存置换时,随机采样若干 Key,淘汰其中最久未使用的键;

这种方法在性能上做了折中,使其接近 LRU 的真实淘汰行为。

LFU

LFU(Least Frequently Used)最不经常使用算法,淘汰规则基于访问频率,淘汰访问频率最低的元素。

近似 LFU 策略

Redis 中使用了一种近似的 LFU 计数器,通过概率更新和衰减机制实现:

  1. 使用 hashmap 为每个 key 维护一个 24 bits 的计数器;

  2. 当 key 被访问时,根据概率函数决定该 key 的访问频率是否需要增加;

  3. 进行内存置换时,随机采样若干 Key,淘汰其中访问频率最低的键;

  4. 通过定时任务,减少访问频率;