Redis 缓存预热、穿透、击穿、雪崩

文章目录

  • [1 什么是缓存](#1 什么是缓存)
  • [2 Redis 为什么能当缓存使用](#2 Redis 为什么能当缓存使用)
  • [3 缓存预热](#3 缓存预热)
    • [3.1 什么是缓存预热?](#3.1 什么是缓存预热?)
    • [3.2 缓存预热解决了什么问题?](#3.2 缓存预热解决了什么问题?)
  • [4 缓存穿透](#4 缓存穿透)
    • [4.1 什么是缓存穿透?](#4.1 什么是缓存穿透?)
    • [4.2 什么时候会发生缓存穿透?](#4.2 什么时候会发生缓存穿透?)
    • [4.3 如何解决缓存穿透问题](#4.3 如何解决缓存穿透问题)
  • [5 缓存击穿](#5 缓存击穿)
    • [5.1 什么是缓存击穿?](#5.1 什么是缓存击穿?)
    • [5.2 怎么解决缓存击穿问题?](#5.2 怎么解决缓存击穿问题?)
  • [6 缓存雪崩](#6 缓存雪崩)
    • [6.1 什么是缓存雪崩?](#6.1 什么是缓存雪崩?)
    • [6.2 如何解决缓存雪崩问题?](#6.2 如何解决缓存雪崩问题?)
  • [7 缓存穿透、击穿、雪崩对比](#7 缓存穿透、击穿、雪崩对比)

1 什么是缓存

缓存是相对而言的,一般是速度快的给速度慢的当缓存.

由于二八定律,大部分请求访问的数据只占总数据的 20%,我们可以把这部分数据提出来,放到处理请求更快的服务器上.

2 Redis 为什么能当缓存使用

  1. Redis 是将数据存储在内存中的,内存的读取速度要比硬盘快几个数量级.
  2. Redis 中的数据结构丰富(String,Hash,List,Set,Zset),适合多种缓存场景
  3. Redis 中的命令执行是单线程的,执行速度快,而且不用担心线程问题.
  4. 支持设置过期时间和淘汰策略,适合做缓存

3 缓存预热

3.1 什么是缓存预热?

当服务启动时,把数据库中的内容取出一部分放入到缓存中.

怎么取数据?

  1. 通过查询日志系统,将高频出现的数据放入缓存
  2. 手动放入缓存

3.2 缓存预热解决了什么问题?

服务器刚启动时,缓存中没有数据,如果没有缓存预热,大量请求会直接打到数据库上.

缓存预热后,可以为数据库挡下一部分请求,缓解数据库压力.

4 缓存穿透

4.1 什么是缓存穿透?

查询数据时,发现 Redis 中没有,数据库中也没有.当这类请求数量很多时,会给数据库带来较大压力.

4.2 什么时候会发生缓存穿透?

  1. 数据校验不严谨
  2. 程序员误操作
  3. 黑客恶意攻击

4.3 如何解决缓存穿透问题

  1. 加强数据校验逻辑
  2. 在 Redis 中存储一个空的键值对,当请求的数据不存在时,直接返回空.
  3. 添加布隆过滤器

布隆过滤器:

  1. 布隆过滤器是一种巧妙的数据结构,采用哈希映射的方式来判断一个元素是否在一个大集合中.它不存储具体数据,空间利用率极高,而且判断速度也快.
  2. 布隆过滤器 = 一个位数组 + 多个哈希函数.
    插入元素时,用哈希函数来算出多个位置,并将位数组对应的位置设置成 1
    查询时,将要查询的元素映射到数组上,看看是否这些位置上都是 1,如果都是 1,说明要查询的这个数据可能存在.只要有一位数字不是 1,则要查询的这个数据一定不存在.

写布隆过滤器时,想到一个疑问: 这个布隆过滤器要怎么维护呢?

插入元素好说,可是如果删除元素呢?肯定不能直接把对应的位置直接置为 0.因为不确定这个位置上的 1 都由哪些元素映射而来的.

我的第一反应是每插入一个元素,对应位置上的数就加一.

可是这样又会有新问题,某个位置上能放下的数字是有限的,

比如用 4 位存计数,范围是 0-15.如果这个位置被映射了超过 15 次,就会从 0 开始重新计数.显然不合理.

那么如果把计数器设置成动态的呢? 让它自己扩容呢?

这样一方面会失去布隆过滤器的占用空间小的特点(要记录每一位用到哪了,以及每一位扩展到哪了).

另一方面,引入动态扩容又会带来问题,动态扩容涉及到内存的重新分配,当多个线程查询时,谁负责扩容?在扩容过程中会不会发送线程安全问题?此时要么加锁,要么用复杂的结构.而且动态扩容会破坏内存的连续性,要用指针进行跳转,如果真的这样做,那么布隆过滤器速度快的特点也就没了.

问了问 AI,告诉我在实际工程中主流的方案是:

  1. 固定位数 + 定期重建

    • 固定位数,插入时对应位置加一,但是对应位置到最大值后就不会再变大了.

    • 定期重建,计数器快满时,重建整个布隆过滤器

    • 在 Redis 中常用"分桶 + 过期 + 重建"(Redis 中哪里用到了布隆过滤器?):

      1. 分桶: 把大过滤器拆成小的.
      2. 过期: 给每个小过滤器设置过期时间
      3. 重建: 小过滤器过期后重建

      Redis 本身的核心数据结构中没有原生的布隆过滤器,它是通过一个名为 RedisBloom 的官方模块来提供的。

      Redis 中的布隆过滤器:RedisBloom 模块

      RedisBloom 是一个概率数据结构模块,为 Redis 增加了包括布隆过滤器在内的多种数据结构。它从 Redis 4.0 开始可用,提供了一组以 BF. 开头的命令来操作布隆过滤器。

  2. 直接换布谷鸟过滤器(天然支持删除).

    • 布谷鸟过滤器的特点:
      1. 支持插入、查询、删除
      2. 空间效率在某些场景下优于布隆过滤器
      3. 代价: 实现更复杂,负载因子高时插入可能失败,需要扩容

5 缓存击穿

5.1 什么是缓存击穿?

当存储在 Redis 中的热点数据过期时,大量请求会直接打到数据库上,给数据库带来巨大压力,甚至导致数据库崩溃.

5.2 怎么解决缓存击穿问题?

  1. 在 Redis 中把热点数据设置成永不过期.
  2. 给热点数据设置一个逻辑上的过期时间.
  3. 添加分布式锁/互斥锁,保证只有一条查询打到数据库上,并重建缓存.
  4. 服务降级,当数据库压力过大时,直接返回默认数据

6 缓存雪崩

6.1 什么是缓存雪崩?

同一时刻,Redis 中的 key 大量过期,或者 Redis 集群宕机,大量请求会直接访问数据库,给数据库带来巨大压力.

6.2 如何解决缓存雪崩问题?

  • 将 key 的过期时间分散开,比如在设置 key 的过期时间时,可以加上一段随机时间.
  • 提高 Redis 集群的可用性

7 缓存穿透、击穿、雪崩对比

缓存穿透 缓存击穿 缓存雪崩
是什么 Redis 和 MySQL 中都不存在要查询的数据 Redis 中的热点数据过期,请求直接打到数据库上 大量 key 同时过期/Redis 集群宕机
范围 单个不存在的数据 单个热点数据 大量 key/整个缓存
原因 参数校验不严格/程序员误操作/黑客恶意攻击 热点 key 过期 key 的过期时间集中/集群宕机
解决方案 加强参数校验,设置布隆过滤器,缓存空值 热点数据永不过期,逻辑过期,互斥锁/分布式锁,服务降级 随机过期时间/提高集群可用性/服务降级
相关推荐
重生之我是Java开发战士1 小时前
【Redis】初识Redis
redis
Wang's Blog2 小时前
Java 项目实战: 外卖平台-数据库环境搭建与十一张表结构解析
java·服务器·redis
喜欢的名字被抢了3 小时前
01-Redis 基础篇:从定位到 Key 管理
redis·教程
Anastasiozzzz4 小时前
重新定义 Agent 基建:Redis 在现代 AI 与智能体系统中的工程实践
java·人工智能·redis·ai
溪语流沙5 小时前
Django + Vue电商项目第001讲:开篇|注册登录加增删改查,那不是电商
redis·python·mysql·docker·typescript·django·vue
努力努力再努力wz5 小时前
【Redis进阶系列】:从主从复制到 Sentinel,一文建立故障检测、Leader 选举与 Failover 的完整心智模型
数据库·redis·缓存
Wang's Blog6 小时前
Java 项目实战: 外卖平台-后台系统登录功能开发
java·服务器·redis
Wang's Blog7 小时前
Java 项目实战: 外卖平台-后台退出功能与首页iframe架构
java·服务器·redis
海天一色y7 小时前
生产级医疗AI Agent:Multi-Agent RAG架构解析
redis·milvus·multi-agent