Redis知识整理二

一、事务

1. 基本原理

使用 MULTI、EXEC、DISCARD、WATCH 四个命令实现。

流程:

  1. MULTI:开启事务
  2. 入队命令:命令不会立即执行,放入队列
  3. EXEC:执行队列中所有命令
  4. 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 *HGETALLSMEMBERSLRANGE 0 -1
  • 高并发下会阻塞主线程,导致雪崩

(2) 批量操作减少 IO

  • MGETHMSET、管道(Pipeline)
  • 一次网络 IO 执行多条命令
  • 性能提升非常明显

(3) 避免大 Key

  • 大 Key 导致网络拥堵、慢查询、迁移卡顿
  • 拆分为多个小 key,或分段存储

(4) 合理设置过期时间

  • 打散过期时间,防止同一时间大量 key 过期导致缓存雪崩

3. 内存与淘汰优化

(1) 使用高效数据结构

  • Hash/List/ZSet 优先使用 ziplist/quicklist
  • 控制编码阈值,节省内存

(2) 开启内存淘汰策略

  • 缓存场景用 allkeys-lruallkeys-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-backlogsomaxconn

(3) 关闭透明巨页 THP

  • 防止 Redis 延迟抖动

六、Redis典型坑点

1. 大 Key 坑(最常见)

  • 表现:
    • 查询慢、网络阻塞、主线程卡顿
    • 集群迁移超时、节点宕机
  • 原因:
    • 一个 key 存了超大字符串、超大集合
  • 后果:高并发下直接导致 Redis 雪崩,阻塞主线程
  • 规避:
    • 拆分成小 key
    • 控制集合大小
    • 定期扫描大 key

2. 慢命令坑(O (N) 命令)

  • 高危命令:
    • KEYS *
    • HGETALLSMEMBERS
    • LRANGE 0 -1
    • FLUSHALL/FLUSHDB
  • 后果:阻塞主线程,整个 Redis 卡死
  • 规避:用 scan 代替 keys,限制查询范围

3. 缓存穿透 / 击穿 / 雪崩

  • 穿透:查不存在的数据,直接打库
  • 击穿:热点 key 过期,瞬间打库
  • 雪崩:大量 key 同时过期 / 节点挂了,数据库压垮
  • 规避:
    • 布隆过滤器、缓存空值
    • 互斥锁、随机过期时间
    • 集群高可用、多级缓存

4. 分布式锁误用坑

  • SETNX 不加过期时间 → 死锁
  • 解锁直接 DEL误删别人锁
  • 锁超时业务没执行完 → 超卖、并发安全问题
  • 主从切换 → 锁丢失
  • 正确姿势:
    • SET key val NX PX
    • Lua 脚本解锁
    • Redisson 看门狗续期

5. 事务不原子、不回滚坑

  • Redis 事务不支持回滚
  • 运行时异常,其他命令照样执行
  • 并发安全靠 WATCH 乐观锁,不是靠事务

6. 集群模式下多 key 操作失效

  • MSETMGETSUNIONLRANGE
  • 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 拆分多副本
相关推荐
qq_330037992 小时前
如何配置ASM元数据备份_md_backup与md_restore重建磁盘组结构
jvm·数据库·python
untE EADO2 小时前
redis的下载和安装详解
数据库·redis·缓存
a9511416422 小时前
SQL触发器实现自动生成流水号_配合序列对象实现递增逻辑
jvm·数据库·python
BduL OWED2 小时前
SQL进阶——JOIN操作详解
数据库·sql·oracle
解救女汉子2 小时前
mysql如何配置元数据锁超时_mysql lock_wait_timeout设置
jvm·数据库·python
下次再写2 小时前
Java互联网大厂面试技术问答实战:涵盖Java SE、Spring Boot、微服务及多场景应用
java·数据库·缓存·面试·springboot·microservices·技术问答
白豆五2 小时前
Redis高级(持久化机制、主从集群、哨兵、分片集群)
数据库·redis·缓存
woniu_buhui_fei2 小时前
Redis知识整理一
数据库·redis·缓存
21439653 小时前
SQL注入防御技术方案_基于正则表达式的输入清洗
jvm·数据库·python