Redis

一、Redis 是什么?

Redis(Remote Dictionary Server)是一个基于内存的键值对数据库,以极快的读写速度著称。

核心特性

特性 说明
基于内存 数据全部存储在内存中,读写速度可达 10 万+ QPS
丰富的数据结构 String、Hash、List、Set、Sorted Set 五种核心类型
持久化 支持 RDB 和 AOF 两种方式,保证数据不丢失
高可用 支持主从复制、哨兵、集群,实现自动故障转移

Redis vs MySQL

对比项 Redis MySQL
存储介质 内存 磁盘
读写速度 微秒级 毫秒级
数据量 受内存限制 可存储海量数据
查询能力 键值查询为主 支持复杂 SQL

两者通常配合使用------Redis 做缓存加速,MySQL 做永久存储。

二、过期删除与内存淘汰

1. 删除策略(三个层次)

Redis 通过三层策略保证内存不会被过期数据占满:

策略 说明
定期删除 每隔 100ms 随机抽取一批 key,删除已过期的
惰性删除 查询 key 时检查是否过期,过期则删除
内存淘汰 内存满时根据淘汰策略主动删除 key

为什么需要三层?

  • 定期删除不能保证所有过期 key 都被选中

  • 惰性删除能补充,但长期不访问的 key 依然存在

  • 内存淘汰兜底,保证 Redis 不会 OOM

2. 八种内存淘汰策略

策略 说明
noeviction 不淘汰,内存满时写操作报错
allkeys-lru 所有 key 中淘汰最近最少使用的
volatile-lru 设置了过期时间的 key 中淘汰 LRU
allkeys-random 所有 key 中随机淘汰
volatile-random 设置了过期时间的 key 中随机淘汰
volatile-ttl 淘汰剩余存活时间最短的
allkeys-lfu(4.0+) 所有 key 中淘汰最少使用的
volatile-lfu(4.0+) 设置了过期时间的 key 中淘汰 LFU

三、缓存三大问题

1. 缓存穿透

定义:查询大量不存在的数据,每次请求都穿透到数据库。

解决方案

  • 布隆过滤器:先过滤掉一定不存在的数据,减轻数据库压力

  • 缓存空值:把未查到的 key 也缓存起来(value 为空),下次直接返回

2. 缓存击穿

定义:一个热点 key 过期瞬间,大量请求同时打到数据库。

解决方案

  • 热点数据永不过期

  • 使用互斥锁,只让一个线程去数据库查询,其他线程等待

3. 缓存雪崩

定义:大批热点 key 在同一时间过期,大量请求涌入数据库,可能导致 MySQL 崩溃。

解决方案

  • 随机设置过期时间:避免同一时刻大批 key 一起过期

  • 热点数据永不过期:核心数据不设过期时间

四、持久化机制

1. RDB(全量快照)

RDB 把内存中的数据全部遍历一遍,以二进制格式存到 .rdb 文件中。

执行流程

  1. 主进程 fork 一个子进程

  2. 子进程遍历内存中的所有数据

  3. 子进程将数据序列化写入 .rdb 文件

  4. 写入完成后替换旧文件

为什么用子进程?

  • 遍历数据会花费不少时间,如果主进程做会阻塞正常读写

  • 子进程做备份不影响主进程处理请求

优缺点

  • 优点:文件小,恢复速度快

  • 缺点:数据丢失风险大(两次备份间的数据可能丢失)

2. AOF(增量日志)

AOF 通过记录所有写操作命令到日志文件,重启时执行这些命令恢复数据。

写入流程

写命令 → aof_buf(内存缓冲区) → 刷盘策略 → AOF 文件(磁盘)

三种刷盘策略

策略 说明 性能 安全性
always 每次写命令都刷盘 最低 最高
everysec 每秒刷一次(默认) 丢失 1 秒数据
no 由操作系统决定 最高 可能丢失大量数据

3. AOF 重写

AOF 文件会越来越大,通过重写压缩文件大小。

重写流程

复制代码
① 主进程 fork 子进程 
② 子进程读取内存数据,生成新的 AOF 文件(只包含最新的数据状态) 
③ 重写期间的新写命令,同时写入 aof_rewrite_buf 缓冲区 
④ 子进程完成后,把 aof_rewrite_buf 中的命令追加到新 AOF 文件 
⑤ 用新文件原子替换旧文件

4. 混合持久化(4.0+)

RDB 文件 + AOF 增量日志,结合两者优点:恢复快 + 数据丢失少。

五、高可用架构

1. 主从复制

工作原理

  1. 主节点负责写操作

  2. 从节点负责读操作

  3. 主节点每次更新数据,都通知从节点同步执行

读写分离的好处:分担主节点压力,提高读性能。

2. 哨兵模式(Sentinel)

哨兵是 Redis 的高可用解决方案,通过独立进程监控主从节点。

核心功能

  • 监控主节点是否存活

  • 主节点故障时自动选举新主节点

  • 故障自动转移,无需人工介入

故障转移流程

复制代码
① 哨兵检测到主节点故障
② 从从节点中选举一个新主节点 
③ 剩余从节点切换为同步新主节点 
④ 旧主节点恢复后,重新变成从节点

3. 新主节点选举规则

优先级 说明
第一 按硬件配置优先级(slave-priority),越高越优先
第二 按复制偏移量,偏移量越大,存储的数据越多,优先选为新主节点

六、Redis 集群(Cluster)

1. 核心设计

  • 16384 个槽位:数据按 key 的 CRC16 值分配槽位

  • 数据分片:每个节点负责一部分槽位

2. 节点加入流程

复制代码
① 新节点通过 CLUSTER MEET 告诉旧节点自己存在 
② 旧节点通过集群总线协议传播给其他成员 
③ 新节点加入后**还没有数据**,需要手动分配槽位

3. 数据访问流程

复制代码
客户端访问 key → 计算槽位(CRC16 % 16384)→ 定位到节点 → 返回数据

七、乐观锁与悲观锁

1. 悲观锁

思想:每次获取数据都以为别人会修改,所以先加锁。

示例:MySQL 的行锁、表锁、读锁、写锁都是悲观锁。

2. 乐观锁

思想:认为数据访问冲突概率很低,所以不加锁,更新时检查版本号。

实现方式

  • 数据增加 version 字段

  • 更新时对比版本号,一致才更新

  • 版本号不一致说明被其他线程改过,操作失败

复制代码
UPDATE table SET value = 新值, version = version + 1
WHERE key = 目标 AND version = 旧版本号

如果影响行数为 0,说明版本号已变化,操作失败。