Redis 核心知识点总结

Redis 核心知识点总结

一、大 Key 问题

1.1 大 Key 判定标准

  • String 类型:单个 Value 数据大小超过 10KB。

  • 集合类型(Hash/List/Set/ZSet):元素数量超过 5000 个,或整体内存占用过大。

1.2 大 Key 引发的问题

  • 阻塞主线程:Redis 命令处理为单线程模型,读取、删除大 Key 会长时间占用主线程,导致其他客户端请求超时、服务卡顿。

  • 集群内存失衡:在 Redis Cluster 集群模式中,大 Key 会造成单个分片内存占用远高于其他节点,引发集群负载不均,影响整体性能。

1.3 大 Key 预防:数据拆分方案

  • Hash 拆分 :将字段数量过万的大 Hash,通过分桶规则(如 key:id % 100)拆分为多个小 Hash,降低单个 Key 的数据体量。

  • List 拆分:若 List 用作队列,保证消息消费速度大于生产速度,避免数据堆积;若用于持久存储,按时间、ID 范围分段拆分存储。

二、Redis 持久化机制

2.1 RDB 持久化(快照持久化)

RDB 是 Redis 的快照持久化方式,会将某一时刻的内存全量数据以二进制文件形式落地到磁盘,触发方式分为四种:

  • 手动触发(BGSAVE) :通过 fork() 创建子进程异步执行快照写入,主线程全程不阻塞,可持续响应客户端请求。

  • 自动触发 :通过配置文件规则触发,例如save 900 1,表示 900 秒内存在 1 次数据修改,自动执行 RDB 快照。

  • 主从同步触发:从节点执行全量数据同步时,主节点会自动生成 RDB 文件,发送给从节点完成数据同步。

  • 停机触发:Redis 正常关机(Shutdown)且未开启 AOF 持久化时,会自动执行一次 RDB 快照持久化。

2.2 AOF 持久化(日志持久化)

AOF(Append Only File)以日志形式持久化数据,会实时记录 Redis 执行的所有写命令(SET、DEL、SADD 等)并落地磁盘。Redis 重启时,通过重放 AOF 日志中的命令,即可完成数据恢复。

2.3 混合持久化(Redis 4.0+ 默认开启)

混合持久化结合了 RDB 高速存储和 AOF 数据高可靠的优势,是目前最优的持久化方案。

核心原理 :AOF 重写阶段,子进程先将当前全量内存数据以 RDB 二进制格式 写入 AOF 文件头部;再将重写过程中产生的增量写命令,以 AOF 文本格式 追加到文件末尾。既保证了文件压缩效率,又避免了全量日志重放的耗时问题。

三、Redis 6.0 多路复用升级(多线程优化)

Redis 6.0 引入 IO 多线程模型,仅优化网络 IO 流程,核心命令执行仍为单线程,完美兼顾并发性能与线程安全。优化后单次请求完整生命周期如下:

3.1 IO 线程组(网络搬运工)

  • 读阶段:负责从 Socket 读取网络字节流,按照 RESP 协议解析为标准 Redis 命令。

  • 写阶段:将主线程处理完成的响应数据,封装为协议标准格式,通过网络发送回客户端。

3.2 主线程(核心大脑)

  • 命令执行:从缓冲区获取解析完成的命令,执行内存读写核心操作(保证单线程安全)。

  • 任务调度:负责监听客户端连接,将待处理的 Socket 请求均匀分发至各个 IO 线程。

四、Pipeline、事务与 Lua 脚本

4.1 Pipeline 管道(网络优化)

Pipeline 是纯网络优化技术,核心作用是减少网络往返耗时:将 N 次网络请求合并为 1 次 RTT 往返,大幅提升吞吐量、降低网络 IO 开销。

核心特性 :Pipeline 批量发送的多条命令,服务端会拆解为独立命令依次执行,无原子性、无隔离性。执行过程中,其他客户端的命令可随时插队,无法保证批量命令连续执行。

4.2 Redis 原生事务(MULTI/EXEC)

Redis 事务是并发控制技术,核心目的是保证批量命令连续执行,不被其他客户端插队,实现命令执行的隔离性。

执行流程 :客户端发送MULTI 开启事务,后续所有命令暂不执行,统一存入服务端事务队列;发送 EXEC 后,批量执行队列内所有命令。

事务异常机制

  • 入队语法错误:命令格式错误、关键字写错等入队失败场景,EXEC 执行时整个事务全部失效,所有命令不执行。

  • 运行时逻辑错误 :命令语法正常但执行逻辑异常(如对 String 类型执行 HSET),错误命令执行失败,正确命令正常执行且不回滚

4.3 Lua 脚本(高性能原子方案)

Redis 2.6 版本内置 LuaJIT 解释器,Lua 脚本与 Redis 核心共享同一进程、同一线程、同一块内存,属于原生级支持,无额外进程、线程开销。

核心优势

  1. 绝对原子性:Lua 脚本执行期间,Redis 单线程独占执行权限,其他所有请求必须排队等待,脚本操作不可中断、不可插队。

  2. 支持复杂编程逻辑:原生事务仅支持简单命令批量执行,Lua 脚本可实现 if-else、循环、变量计算等复杂逻辑。

  3. 消除网络空窗期:可在服务端完成「读取-判断-写入」完整业务闭环,无需客户端交互,彻底规避网络往返导致的并发安全问题。

五、Redisson 分布式锁

5.1 Lua 锁的痛点:锁超时问题

单纯 Lua 脚本可保证加锁操作原子性,但无法解决锁超时失效问题:业务设置锁过期时间(如 10s),若因 Full GC、下游接口卡顿导致业务执行超时(如 12s),锁会自动过期释放,其他线程可抢占锁,引发分布式锁失效、并发安全问题。

5.2 Redisson 核心原理

Redisson 底层基于大量优化后的 Lua 脚本实现加锁、续期、解锁逻辑,依托 Lua 脚本的独占原子性,保证「锁存在判断-哈希表设置-过期时间配置」整套操作不可分割,原子性、并发安全性优于原生 MULTI/EXEC 事务。

5.3 看门狗(Watch Dog)续期机制

专门解决锁超时误释放问题,是 Redisson 分布式锁的核心特性,默认锁超时时间 30s,续期间隔 10s。

执行流程

  1. 线程 A 加锁成功后,自动启动后台看门狗定时线程;

  2. 每隔 10s(默认 lockWatchdogTimeout/3)检测持有锁的业务线程是否存活;

  3. 若业务未执行完毕、线程存活,通过 Lua 脚本将锁 TTL 重新刷新为 30s;

  4. 业务执行完成后,主动释放锁,同时关闭看门狗线程。

六、Redis 缓存三大异常

6.1 缓存穿透

问题定义:客户端查询的 Key,在缓存和数据库中均不存在,请求直接穿透到数据库,大量无效请求会压垮数据库。

核心解决方案:布隆过滤器

数据更新方案

  • 实时更新(主流方案):业务写入数据库的同时,同步调用布隆过滤器新增数据。优点是实时性强,新数据可立即拦截无效查询;缺点是会增加一次网络 IO 开销。

  • 定时全量重建:针对数据变动少、物理删除多的场景,凌晨通过定时任务遍历数据库有效数据,重建布隆过滤器并替换旧过滤器。优点是不影响业务写入性能;缺点是实时性差,新数据短时间内可能穿透。

Java 集成示例(Redisson)

java 复制代码
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("userList");
// 初始化:预期存储100万数据,误判率1%
bloomFilter.tryInit(1000000L, 0.01);

// 添加有效数据
bloomFilter.add("user_123");

// 业务拦截判断
if (bloomFilter.contains("user_456")) {
    // 数据存在,执行后续业务
}

核心参数说明

  • 预期插入量(n):预估过滤器长期存储的不重复 Key 数量,建议预留未来 1-2 年数据量。

  • 误判率(fpp) :允许穿透到数据库的无效请求比例,常规设置 1%(0.01)或 0.1%(0.001)。当你设置了 n n n 和 f p p fpp fpp 后,底层库会自动帮你计算出最优的 m m m 和 k k k:如果你把 n n n 设小了:随着存入数据超过预期,位数组中 1 的密度会迅速增大。当数组几乎全被填满时,任何查询都会返回"可能存在",失去拦截意义。如果你把 f p p fpp fpp 设得极低:虽然更精确了,但会导致位数组 m m m 变得极大(占用更多内存),且哈希函数 k k k 变多(增加计算 CPU 开销)。

布隆过滤器痛点与优化

底层通过位数组、哈希函数实现,初始化后无法动态扩容。数据超预期会导致误判率飙升。

优化方案:充足预估初始容量、分段部署过滤器、定时全量重建。

6.2 缓存击穿

问题定义热点 Key 过期瞬间,海量并发请求无缓存可用,全部直接涌入数据库,瞬间压垮 DB。常见场景:电商爆款商品、热门资讯、排行榜、系统基础字典。

主流解决方案

  1. 逻辑过期方案(最优):Redis 数据不设置物理过期时间,将过期时间存入数据 JSON 字段。检测到数据过期后,直接返回旧缓存数据,同时启动异步单线程更新数据库数据、刷新缓存。无锁竞争、性能无损,适配超高读流量场景,可容忍少量脏数据。

  2. Redisson 分布式锁:缓存失效时,仅一个请求获取锁更新缓存,其他请求短暂休眠后重试查询缓存。并发可控,适配分布式集群场景。

  3. 本地 JVM 锁(轻量方案):使用 synchronized、ReentrantLock 加锁。微服务多节点部署时,仅节点数量级请求会穿透到 DB,压力极小,无分布式锁开销。

七、Redis 过期与内存淘汰策略

7.1 惰性删除(被动删除)

原理:Key 过期后不会主动删除,仅当客户端再次访问该 Key 时,Redis 才校验过期状态,若已过期则立即删除并返回空。

优缺点:极致节省 CPU 资源,无额外巡检开销;但大量过期冷数据无人访问时,会长期占用内存,形成「内存幽灵」,造成内存泄漏。

7.2 定期删除(主动删除)

原理:为解决惰性删除的内存堆积问题,Redis 默认每秒执行 10 次内存巡检(hz=10),采用抽样检测机制,而非全量扫描:

  1. 从过期键空间随机抽取 20 个 Key;

  2. 删除其中所有已过期的 Key;

  3. 若过期 Key 占比超 25%,立即重复抽样删除,直至过期数据大幅减少;

  4. 严格限制单次巡检最大耗时(默认 25ms),避免主线程阻塞。

7.3 内存淘汰策略

当惰性删除、定期删除均无法清理足够数据,Redis 内存达到 maxmemory 上限时,触发内存淘汰,核心两种策略:

  • LRU(最近最少使用):基于访问时间淘汰,优先删除长期未被访问的冷数据。

  • LFU(最不经常使用):基于访问频次淘汰,优先删除单位时间内访问次数最少的数据。可解决 LRU 策略中「冷数据偶尔访问变为热数据、长期占用内存」的问题,淘汰精度更高。

八、Redis 秒杀高并发优化方案

8.1 分布式锁秒杀痛点

传统分布式锁秒杀的本质是并发转串行,海量请求同时抢锁时,仅单个线程可执行业务,其余大量线程阻塞排队。会直接榨干 Tomcat 线程池,导致整体服务瘫痪、接口 RT 飙升、用户体验极差。

8.2 无锁秒杀最优方案

利用 Redis 单线程命令原子性,彻底摒弃分布式锁,实现超高并发秒杀:

  1. 提前将秒杀库存预载入 Redis(如 set goods:154:stock 100);

  2. 客户端请求进来后,直接执行原子递减命令 DECRBY goods:154:stock 1,或通过 Lua 脚本封装「库存≥1 才递减」的判断逻辑;

  3. 命令返回值 ≥0 则秒杀成功,否则直接返回售罄。

核心优势:无需加锁、无线程阻塞,Redis 单机原子递减可支撑 10w+/s 并发,未命中请求瞬间返回结果,快速释放 Tomcat 线程,彻底解决高并发服务雪崩问题。

相关推荐
basketball6161 小时前
Redis基础:6. 哨兵模式
数据库·redis·bootstrap
点灯小铭1 小时前
基于单片机的锅炉压力与温度监测报警系统设计
数据库·单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
程序员二叉1 小时前
【Java】 面试核心合集:BigDecimal、缓存池、多态、反射全解析
java·缓存·面试
麦聪聊数据1 小时前
AI+Headless Agent 如何构建零风险数据库运维体系
数据库
小小工匠1 小时前
Redis - CPU架构对Redis性能的影响
数据库·redis·架构
超梦dasgg1 小时前
连接 & 连接池完整详解(以数据库连接最常用,Redis/MQ 同理)
数据库·redis·缓存
编程探索者小陈2 小时前
MySQL 数据库入门与实战教程(二)
数据库
闪电悠米2 小时前
黑马点评-秒杀优化-03_blocking_queue_async_order
数据库·分布式·oracle·junit·wpf·lua
Python私教2 小时前
免费用上 GPT-4 级模型:国产大模型 API 接入教程(2026 最新版)
数据库