一、事务
1. 基本原理
使用 MULTI、EXEC、DISCARD、WATCH 四个命令实现。
流程:
MULTI:开启事务- 入队命令:命令不会立即执行,放入队列
EXEC:执行队列中所有命令DISCARD:放弃事务,清空队列
2. Redis事务3大特性
- 隔离性: 事务执行期间,不会被其他客户端命令打断,命令一次性、顺序执行。
- **批量执行:**一次 EXEC 提交所有命令,减少网络开销。
- WATCH 乐观锁
WATCH key:监听 key,事务执行前如果 key 被修改- 执行
EXEC时事务直接失败返回 nil,实现乐观锁。
3. Redis 事务 不保证 ACID
- 不支持原子性(传统意义上)
- 命令队列中部分命令失败 ,其余命令仍然会执行 ,不会回滚。
- 比如语法错会整个失败;运行时报错不影响其他命令。
- **不支持回滚:**Redis 设计追求简单高效,不提供回滚机制。
- **无持久性:**事务执行完只是在内存,是否持久化看 RDB/AOF。
4. 两种异常情况
- 入队时语法错误: 执行 EXEC 后整个事务全部拒绝执行。
- 执行时运行错误: 比如对 String 执行 LPOP,出错命令失败,其他命令照常执行,不回滚。
5. 典型应用场景
- 秒杀、扣减库存(配合 WATCH)
- 批量操作减少网络 IO
- 分布式锁 + 事务保证操作原子性
二、分布式锁
1、基础实现:SET 加锁
SET lock_key unique_value NX PX 30000
- NX:仅 key 不存在时才设置(互斥)
- PX 30000:过期时间,防止死锁
- unique_value:唯一标识(UUID / 线程 ID),用于安全解锁
2. 为什么要带唯一值?
防止误删别人的锁:
- 线程 A 加锁 → 执行业务超时 → 锁自动过期
- 线程 B 加锁成功
- 线程 A 执行完,直接
DEL lock_key会删掉 B 的锁
正确解锁方式(Lua 脚本原子执行):
Lua
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
3. 三大核心问题
① 锁过期,业务还没执行完?
→ **锁自动续期(看门狗机制)**Redisson 已经内置实现。
- 开启后台线程,定时检查锁是否持有
- 快过期时自动延长过期时间。
② 主从切换导致锁丢失?
→ Redis 主从异步复制存在缺陷
主机加锁成功 → 还没同步到从机 → 主机宕机 → 从机升主 → 锁丢失
解决方案:
- Redlock 红锁(官方算法)
- 对多个独立 Redis 节点加锁,多数成功才算加锁成功
生产一般用 Redisson 封装好的 Redlock。
③ 并发竞争、不可重入?
→ 可重入锁
用 Hash 结构存储:lock_key → {线程id: 重入次数}
Redisson 也已实现。
4. Redisson 分布式锁(企业标准方案)
功能非常完善,开箱即用:
- 可重入
- 自动续期(看门狗)
- 公平锁
- 联锁、红锁
- 读写锁底层就是 Lua + 自动续期
三、集群模式
1. 主从复制(Master-Slave)
- 作用:读写分离 + 数据备份
- 一主多从
- 原理
- 从库首次全量同步(RDB)
- 后续增量同步(命令传播)
- 优点:减轻主节点读压力
- 缺点:无自动故障转移,主节点挂了需手动切换
2. 哨兵(Sentinel)
- 作用:高可用HA(High Availability,无单点故障、自动故障转移),监控主从
- 核心功能:
- 监控节点状态
- 自动故障转移:主挂了自动选从升主
- 通知、配置提供者
- 一般至少 3 个哨兵节点,通过投票选主
- 优点:自动容灾
- 缺点:不支持分片,数据都在一台主节点,受内存上限限制
3. Redis Cluster(集群分片)
核心特点
- 自动分片,突破单机内存限制
- 去中心化,无中心节点
- 自带高可用HA(主从 + 故障转移)
槽位机制
- 总共 16384 个哈希槽(slot)
- 公式:**
CRC16(key) % 16384**决定 key 落在哪个节点 - 集群把槽分配到不同主节点
- 增删节点只需迁移槽位,无需停机
- 为什么是16384个槽?兼顾消息大小、传输效率、节点扩容上限
高可用
- 每个主节点配至少 1 个从节点
- 主节点挂了,哨兵机制自动选举从节点升主
优缺点
- 优点:水平扩容、高可用、去中心化
- 缺点:
- 不支持跨节点事务、批量操作
- 不支持多 key 命令(如 mset、sinter)除非同槽
- 槽迁移会有短暂卡顿
4. 集群常见问题
- 跨槽事务不支持
- 批量操作有限制(mget/mset 建议 hashtag)
- 扩容 / 缩槽需迁移,会短暂不可用
- 事务、Lua 尽量在同节点执行
四、持久化机制
1. RDB(Redis Database)------ 快照持久化
- 原理 :定时 对内存做全量快照 ,生成二进制
.rdb文件,保存某一时刻的所有数据。 - 触发方式:
- 手动:
SAVE(阻塞)、BGSAVE(fork 子进程,非阻塞) - 自动:配置文件
save 60 1000满足条件自动 BGSAVE
- 手动:
- 优点:快照全量备份,文件小、恢复快
- 缺点:宕机丢数据
- 适合:冷备、数据允许少量丢失
2. AOF(Append Only File)------ 日志持久化
- 原理 :把每一条写命令 以文本形式追加到
.aof文件,重启时重放命令恢复数据。 - 三种刷盘策略:
- always:每次写都刷盘 → 最安全,性能差
- everysec::每秒刷一次 → 默认,兼顾安全与性能
- no:由操作系统决定 → 最快,最不安全
- 优点:数据安全性高,最多丢 1 秒数据;可读可编辑,可修复误操作
- 缺点:文件比 RDB 大很多;恢复速度比 RDB 慢
3. 混合持久化(Redis 4.0+)
- RDB 全量 + AOF 增量: 重写 AOF 时,先写**RDB 快照,**再把后续命令以 AOF 方式追加
- 兼顾恢复速度与数据安全性
- 生产标配
- 优点:恢复快(像 RDB)、丢数据少(像 AOF)
生产建议:开启 AOF everysec,配合 RDB 做冷备,使用 混合持久化
五、高并发场景优化
1. 架构层面
(1) 读写分离
- 主节点写,从节点读
- 大量读请求分摊到从库,扛高并发
(2) Redis Cluster 分片
- 数据分散到多主节点
- 突破单机 QPS、内存瓶颈
- 横向扩展,并发能力成倍提升
(3) 多级缓存
- 本地缓存(Caffeine/Cache)+ Redis
- 热点数据直接本地命中,减少 Redis 压力
2. 命令与使用优化
(1) 禁用 O (N) 命令
KEYS *、HGETALL、SMEMBERS、LRANGE 0 -1- 高并发下会阻塞主线程,导致雪崩
(2) 批量操作减少 IO
MGET、HMSET、管道(Pipeline)- 一次网络 IO 执行多条命令
- 性能提升非常明显
(3) 避免大 Key
- 大 Key 导致网络拥堵、慢查询、迁移卡顿
- 拆分为多个小 key,或分段存储
(4) 合理设置过期时间
- 打散过期时间,防止同一时间大量 key 过期导致缓存雪崩
3. 内存与淘汰优化
(1) 使用高效数据结构
- Hash/List/ZSet 优先使用 ziplist/quicklist
- 控制编码阈值,节省内存
(2) 开启内存淘汰策略
- 缓存场景用
allkeys-lru或allkeys-lfu - 保证热点数据常驻内存
(3) 避免频繁内存交换
- 禁止使用 Swap
- maxmemory 预留安全空间,不要打满
4. 并发安全优化
(1) 分布式锁用 Redisson
- 可重入 + 自动续期 + 阻塞等待
- 避免锁超时、死锁、误删
(2) 乐观锁控制并发
- 使用
WATCH+ 事务 - 适用于秒杀、库存扣减
(3) 限流保护
- 利用 Redis + Lua 实现滑动窗口限流
- 防止流量打垮 Redis
5. 高可用与稳定性
(1) 开启 AOF + RDB 混合持久化
- 数据安全 + 恢复快
(2) 主从 + 哨兵 / Cluster
- 自动故障转移,避免单点
(3) 禁用长时间阻塞操作
- 不要在 Redis 执行 Lua 复杂计算
- 不要大量 RENAME、FLUSHALL
6. 网络与配置优化
(1) 使用连接池
- 合理设置最大连接数、超时时间
(2) 调整 TCP 内核参数
tcp-backlog、somaxconn等
(3) 关闭透明巨页 THP
- 防止 Redis 延迟抖动
六、Redis典型坑点
1. 大 Key 坑(最常见)
- 表现:
- 查询慢、网络阻塞、主线程卡顿
- 集群迁移超时、节点宕机
- 原因:
- 一个 key 存了超大字符串、超大集合
- 后果:高并发下直接导致 Redis 雪崩,阻塞主线程
- 规避:
- 拆分成小 key
- 控制集合大小
- 定期扫描大 key
2. 慢命令坑(O (N) 命令)
- 高危命令:
KEYS *HGETALL、SMEMBERSLRANGE 0 -1FLUSHALL/FLUSHDB
- 后果:阻塞主线程,整个 Redis 卡死
- 规避:用 scan 代替 keys,限制查询范围
3. 缓存穿透 / 击穿 / 雪崩
- 穿透:查不存在的数据,直接打库
- 击穿:热点 key 过期,瞬间打库
- 雪崩:大量 key 同时过期 / 节点挂了,数据库压垮
- 规避:
- 布隆过滤器、缓存空值
- 互斥锁、随机过期时间
- 集群高可用、多级缓存
4. 分布式锁误用坑
- 只
SETNX不加过期时间 → 死锁 - 解锁直接
DEL→ 误删别人锁 - 锁超时业务没执行完 → 超卖、并发安全问题
- 主从切换 → 锁丢失
- 正确姿势:
SET key val NX PX- Lua 脚本解锁
- Redisson 看门狗续期
5. 事务不原子、不回滚坑
- Redis 事务不支持回滚
- 运行时异常,其他命令照样执行
- 并发安全靠
WATCH乐观锁,不是靠事务
6. 集群模式下多 key 操作失效
MSET、MGET、SUNION、LRANGE等- key 不在同一个 slot → 报错或数据不对
- 解决:
- 用
{tag}强制同槽 - 业务层自己组装
- 用
7. 过期键不及时删除
- Redis 是惰性删除 + 定期删除
- 大量冷数据过期 key 会占内存
- 配合内存淘汰策略才能彻底清理
8. 持久化配置不当
- 不设 AOF → 宕机丢数据
- AOF 不重写 → 文件巨大,重启极慢
- RDB 频繁 fork → 内存翻倍、卡顿
- 推荐:4.0+ 混合持久化
9. 主从延迟 + 数据不一致
- 主从异步复制
- 刚写立刻读,可能从库读旧数据
- 解决方案:
- 关键读写走主
- 监控延迟,阈值自动切主
10. 连接池使用不当
- 连接不够 → 大量超时
- 连接不释放 → 连接泄漏
- 最大连接设置不合理 → Redis 被占满拒绝服务
11. 内存使用失控
- 不设置
maxmemory - 淘汰策略用
noeviction - 内存打满后新写入直接报错
- 缓存场景推荐:
allkeys-lru
12. Hot Key 热点坑
- 一个超级热 key 打满单节点
- Cluster 分片也没用,节点被打垮
- 解决:
- 本地缓存
- 热点 key 拆分多副本