一、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 文件中。
执行流程:
-
主进程 fork 一个子进程
-
子进程遍历内存中的所有数据
-
子进程将数据序列化写入
.rdb文件 -
写入完成后替换旧文件
为什么用子进程?
-
遍历数据会花费不少时间,如果主进程做会阻塞正常读写
-
子进程做备份不影响主进程处理请求
优缺点:
-
优点:文件小,恢复速度快
-
缺点:数据丢失风险大(两次备份间的数据可能丢失)
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. 主从复制
工作原理:
-
主节点负责写操作
-
从节点负责读操作
-
主节点每次更新数据,都通知从节点同步执行
读写分离的好处:分担主节点压力,提高读性能。
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,说明版本号已变化,操作失败。