Redis数据库——Redis雪崩、穿透、击穿

本文先简要介绍为什么需要使用Redis,以及过期键的删除策略,进而详细介绍Redis雪崩、穿透、击穿的发生场景和解决方案。

文章目录

前情提要

为什么使用redis?

  1. 提高性能:缓存査询速度比数据库查询速度快(内存Vs硬盘);
  2. 提高井发能力:缓存分担了部分请求,支持更高的并发。

Redis 的过期键删除策略

Redis 为管理内存,对设置了过期时间的键采用了以下三种删除策略:

  1. 定时过期

    • 描述:为每个设置了过期时间的键创建一个定时器,到达过期时间立即清除。
    • 优点:对内存很友好,过期数据能及时清除。
    • 缺点:需要消耗大量的 CPU 资源来处理定时器,影响缓存响应时间和吞吐量。
  2. 惰性过期

    • 描述:只有在访问某个键时才判断其是否过期,过期则清除。
    • 优点:最大化节省 CPU 资源。
    • 缺点:可能会有大量过期键未被访问而占用内存。
  3. 定期删除

    • 描述 :每隔一定时间扫描 expires 字典中的部分键,清除过期键。
    • 优点:折中策略,通过调整扫描时间间隔和每次扫描数量,平衡 CPU 和内存资源。

默认使用惰性过期 (Lazy Expiration)和定期删除 (Periodic Deletion)两者结合的方式,能够在性能和内存使用之间找到一个良好的平衡。

数据读取流程

Redis 的数据读取通常遵循以下步骤:

  1. 缓存命中:如果数据在缓存中存在,直接从缓存中读取。
  2. 缓存未命中:如果缓存中没有数据,则查询数据库,获取数据后写入缓存供下次使用。

三种问题及解决方案

  • 缓存雪崩:主要解决缓存大规模失效问题,核心在于错峰和高可用。
  • 缓存穿透:主要解决请求不存在数据的问题,核心在于布隆过滤器和空值缓存。
  • 缓存击穿:主要解决热点数据失效问题,核心在于互斥锁和逻辑过期。

1. 缓存雪崩

定义 :在某一时间段内,缓存集中过期或 Redis 服务宕机,导致大量请求直接涌向数据库,可能引发数据库崩溃。

原因

内存昂贵且有限,所以Redis需要给数据设置过期时间,将过期键数据删除。

  • 缓存中的大量数据设置了相同的过期时间,导致集中失效。
  • 缓存服务宕机或崩溃,所有缓存失效。

解决方案

  1. 键值------缓存失效时间错峰

    • 给缓存的过期时间增加一个随机值,减少同一时间段的缓存同时过期。
    bash 复制代码
    SET key value EX 300 + random(60)  # 过期时间加随机值
  2. 事发前------Redis 高可用架构

    • 实现 Redis 主从架构或 Redis Cluster,避免单点故障。
    • 使用 Sentinel(哨兵)进行故障转移,尽量避免Redis挂掉这种情况发生。
  3. 事发中------本地缓存和限流

    • 在 Redis 宕机时,启用本地缓存(如 Ehcache)。
    • 通过限流(如 Hystrix)保护数据库(起码能保证我们的服务还是能正常工作的)。
  4. 事发后------Redis 持久化

    • 开启 RDB 或 AOF 持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

2. 缓存穿透

定义:用户请求的键在缓存和数据库中都不存在,导致每次请求都会直接访问数据库。

为什么说键在数据库中也不存在 呢?

因为如果键在数据库中存在,第一次命中,就会写入缓存,下次就不会请求到数据库,不属于缓存穿透

原因

  • 恶意攻击:通过大量请求不存在的键对系统进行攻击。例如 ID 为负数或不存在的用户数据。
  • 数据不全:一些正常请求因为数据未命中而直接访问数据库。

解决方案

  1. 布隆过滤器

    • 在缓存前引入布隆过滤器,用于判断请求的键是否可能 存在:
      • 如果布隆过滤器判断不存在,直接返回,无需访问缓存和数据库。
      • 如果布隆过滤器判断可能存在,再访问缓存或数据库。
    bash 复制代码
    # 添加数据到布隆过滤器
    BF.ADD filter "valid_key"
    # 查询数据是否存在
    BF.EXISTS filter "invalid_key"  # 返回 false,直接拦截请求
  2. 缓存空值

    • 当查询结果为空时,将空值存入缓存,并设置较短的过期时间。
    bash 复制代码
    SET key "null" EX 60  # 缓存空值 60 秒

    这种情况我们一般会将空对象设置一个较短的过期时间(时间太长的话,万一数据库中已经有数据了,但是长时间命中redis发现没有数据,导致用户拿不到数据)。

  3. 参数校验

    • 对输入的参数进行校验,避免无效请求到达后端。
  4. 限流防护

    • 对频繁请求不存在键的客户端进行限制,防止恶意攻击。

3. 缓存击穿

定义 :当缓存中某个高频访问的热点键过期时,大量请求同时到达数据库,造成数据库压力骤增。

场景

  • 一个热点数据被大量访问,且缓存突然失效,失效后请求全部打到数据库。

解决方案

  1. 热点键永不过期

    • 热点键不设置过期时间,直接通过覆盖更新来保持数据一致性。
  2. 加互斥锁

    • 使用 Redis 或 Zookeeper 的分布式锁 ,控制只有一个线程能访问数据库并更新缓存,其余线程等待。
    bash 复制代码
    SET lock:key "unique_value" NX EX 10  # 设置分布式锁
  3. 热点键限流

    • 对热点键的请求进行限流,避免短时间内大量请求涌入。
  4. 热点数据分片

    • 将热点数据分散到不同的 Redis 节点或分布式服务中,减少单点压力。

对比总结

问题 定义 原因 解决方案
缓存雪崩 大量缓存数据同时失效,导致请求集中打到数据库或服务 缓存失效时间一致,缓存服务宕机 错峰失效、缓存预热、高可用集群、限流降级
缓存穿透 请求的键既不在缓存中,也不在数据库中 恶意攻击、数据不全 布隆过滤器、空值缓存、参数校验、限流防护
缓存击穿 热点数据缓存失效时,大量请求同时查询该数据 热点数据失效,大量请求集中到数据库 互斥锁机制、逻辑过期、请求分流、分布式限流
相关推荐
Acrelhuang12 分钟前
8.3MW屋顶光伏+光储协同:上海汽车变速器低碳工厂的能源革命-安科瑞黄安南
大数据·数据库·人工智能·物联网·数据库开发
喝醉的小喵16 分钟前
分布式环境下的主从数据同步
分布式·后端·mysql·etcd·共识算法·主从复制
雷渊39 分钟前
深入分析mybatis中#{}和${}的区别
java·后端·面试
崖山数据库系统YashanDB40 分钟前
YashanDB json语法
数据库
陈三一43 分钟前
关于多数据源下Spring声明式事务管理失效问题的分析与解决
数据库·spring
亦是远方1 小时前
2025华为软件精英挑战赛2600w思路分享
android·java·华为
花月C1 小时前
Spring IOC:容器管理与依赖注入秘籍
java·开发语言·rpc
ylfhpy1 小时前
Java面试黄金宝典22
java·开发语言·算法·面试·职场和发展
我有医保我先冲1 小时前
SQL复杂查询与性能优化全攻略
数据库·sql·性能优化
烧瓶里的西瓜皮1 小时前
Go语言从零构建SQL数据库引擎(2)
数据库·sql·golang