description: 从持久化、主从哨兵、分片集群到多级缓存落地,再到 BigKey、Pipeline、慢查询与安全加固,系统梳理 Redis 高级能力。
在掌握 Redis 基础命令之后,一到线上就会遇到:单机瓶颈、高可用、数据一致性、缓存击穿、BigKey、慢查询、安全风险……本文把讲义里的“高级必修课”整理成一篇可直接发布的系统教程,覆盖架构、原理和落地代码思路。
⚡ 快速参考(先给答案)
- 你何时需要高级篇:单机 Redis 扛不住、数据太多、需要自动故障转移、需要更高吞吐/更低延迟、多层缓存治理、缓存一致性
- 核心结论:
- Redis 作为缓存时,不必强求复杂持久化,但必须做好高可用与治理(慢查询/BigKey/安全)
- 主从 + 哨兵优先满足大部分业务;万不得已再上大规模分片集群
- 多级缓存能把压力从 Tomcat/数据库“分流”,但引入 OpenResty/Lua 后要做好工程化与一致性
- 最短路径:
- 高可用:主从 -> 哨兵(自动故障转移)
- 海量数据&写扩展:分片集群(hash slot)
- 性能体系:浏览器缓存 -> Nginx/OpenResty 本地缓存 -> Redis -> JVM 本地缓存 -> DB
- 避坑提醒:生产禁用/限制
KEYS、FLUSHALL、CONFIG SET;重点治理 BigKey、慢查询阈值、序列化与 key 设计
📚 学习目标
- 理解 Redis 的两种持久化、主从同步、哨兵故障转移、分片集群 hash slot 原理。
- 搭建“多级缓存”体系,知道每一层缓存解决什么问题、带来什么风险。
- 掌握线上最佳实践:key 设计、BigKey 治理、批处理优化、慢查询与安全加固。
一、基础概念(是什么)
1.1 单机 Redis 的四大问题(为什么要上集群)
单机 Redis 常见瓶颈集中在:
- 数据丢失风险:进程宕机、机器故障(需要持久化/复制)
- 并发能力上限:单实例吞吐有限(需要读写分离/水平扩展)
- 海量数据存储:内存受限(需要分片)
- 高可用:主节点宕机后要自动切换(需要哨兵/集群能力)
1.2 多级缓存是什么(为什么要多级)
传统“Tomcat -> Redis -> DB”会有两个典型问题:
- 请求都要进 Tomcat,Tomcat 成为系统瓶颈
- Redis 缓存失效时,对 DB 形成瞬时冲击
多级缓存把缓存前移和下沉:
- 浏览器缓存(静态资源)
- Nginx/OpenResty 本地缓存(shared dict)
- Redis 分布式缓存
- Tomcat JVM 本地缓存(Caffeine)
- DB
二、原理详解(为什么这样做)
2.1 Redis 持久化:RDB vs AOF
Redis 常见持久化两种:
- RDB(快照):定期把内存数据生成快照文件(dump.rdb)
- AOF(追加日志):把每次写命令追加记录到 aof 文件
2.1.1 RDB 执行时机与原理
RDB 触发方式:
save(阻塞,少用)bgsave(子进程异步)- Redis 停机时
redis.conf中配置触发条件,例如:
save 900 1 save 300 10 save 60 10000RDB 的关键点:bgsave会fork子进程,利用copy-on-write,子进程写 RDB,主进程继续响应请求。
RDB 缺点:两次快照间隔期可能丢数据;fork/压缩/写盘耗时。
2.1.2 AOF 策略与重写
AOF 开关(redis.conf):
appendonly yes appendfilename "appendonly.aof"刷盘策略:
appendfsync always:最安全,性能差appendfsync everysec:默认,性能与安全平衡(常用)appendfsync no:交给 OS,风险高
AOF 重写:bgrewriteaof会把“多次覆盖写”压缩成最少命令,减少 AOF 体积。
2.1.3 选型建议
- 作为“缓存”的 Redis:优先保证可用性与性能,持久化不一定必须(看业务容忍度)
- 需要更高数据安全:RDB + AOF 组合更稳
2.2 主从复制:全量同步 vs 增量同步
主从核心价值:读写分离 + 数据备份。
2.2.1 全量同步
第一次建立主从关系时:
- slave 发送自己的
replid与offset - master 发现
replid不一致,触发全量同步 - master 生成 RDB 发给 slave,slave 清空旧数据并加载
- master 把同步期间的写命令记录到
repl_backlog并补发给 slave
2.2.2 增量同步与 repl_backlog
slave 恢复连接时带上 offset,master 从repl_backlog里找 offset 之后的命令增量补齐。
注意:repl_backlog是固定大小环形数组,如果 slave 断开太久导致 offset 被覆盖,只能再做全量同步。
2.2.3 主从优化建议
- 开启无磁盘复制:
repl-diskless-sync yes(降低全量同步磁盘 I/O) - 合理增大
repl_backlog,减少被覆盖导致的全量同步 - slave 太多时用“主-从-从”链式结构,降低 master 压力
2.3 哨兵 Sentinel:自动故障转移
哨兵三大作用:
- 监控:持续
ping检测 master/slave - 故障转移:master 宕机自动提升 slave 为 master
- 通知/服务发现:把新 master 信息通知给客户端
2.3.1 主观下线与客观下线
- 主观下线:单个 sentinel 判断实例超时未响应
- 客观下线:达到 quorum 的 sentinel 都认为下线
2.3.2 选主规则(面试常问)
大致顺序:
- slave 与 master 断开时间太久(超过阈值)直接淘汰
slave-priority越小优先级越高(0 永不参与)- offset 越大数据越新优先级越高
- 运行 id 越小优先级越高
2.3.3 Spring/Lettuce 客户端如何适配哨兵
Spring Data Redis + Lettuce 能感知 sentinel 的主从变化并自动切换。
配置示例:
spring:redis:sentinel:master:mymasternodes:-192.168.150.101:27001-192.168.150.101:27002-192.168.150.101:27003并配置读策略(读写分离):
@BeanpublicLettuceClientConfigurationBuilderCustomizerclientConfigurationBuilderCustomizer(){returnbuilder->builder.readFrom(ReadFrom.REPLICA_PREFERRED);}2.4 分片集群:海量数据与写扩展
主从/哨兵解决了高可用与读扩展,但海量数据与写扩展需要分片集群。
2.4.1 hash slot(16384 插槽)原理
Redis Cluster 把 key 映射到 0~16383 插槽,插槽再分配到不同 master:
- key 含
{}:{}内是“有效部分” - key 不含
{}:整个 key 是有效部分
有效部分做 CRC16 哈希,对 16384 取余得到 slot -> 路由到对应节点。
2.4.2 hash tag 的用法
如果希望同一类 key 落同一个 slot(方便事务/lua/批处理):
{user:1001}:profile {user:1001}:orders有效部分相同 -> slot 相同 -> 节点相同。
三、完整实战代码(怎么做)
3.1 多级缓存的落地架构(目标形态)
请求路径示例(商品详情接口):
浏览器 -> Nginx 反向代理 -> OpenResty(本地缓存 + Redis)-> Tomcat 集群(JVM 缓存)-> DB
关键点:
- OpenResty 需要 Lua 编程(shared dict、本地缓存;读 Redis;回源 Tomcat)
- Tomcat 内用 Caffeine 做 JVM 本地缓存
3.2 JVM 进程缓存:Caffeine(Tomcat 层)
缓存适用:访问频繁、数据量较小、追求极致性能的查询(无网络开销)。
Caffeine 核心用法(思路):
- 定义
Cache<K, V>bean cache.get(key, k -> 查询DB):未命中回源 DB- 设置容量上限/过期策略避免内存撑爆
常用策略:
- 基于容量:
maximumSize - 基于时间:
expireAfterWrite
3.3 OpenResty:Nginx 编程(本地缓存 + Redis + 回源)
OpenResty 通过lua_shared_dict提供 worker 共享本地缓存:
lua_shared_dict item_cache 150m;Lua 层读写:
item_cache:get(key)item_cache:set(key, val, expireSeconds)
最终查询函数思路(伪代码):
read_data(key): 1) 查本地缓存 2) 未命中 -> 查Redis 3) 仍未命中 -> 回源Tomcat(http) 4) 写回本地缓存(不同数据不同TTL) 5) 返回3.4 Redis 缓存预热(避免冷启动打爆 DB)
冷启动:服务刚启动 Redis 没缓存,大量请求回源 DB。
预热思路:
- 项目启动后,批量查询热点(或全量)数据
- 写入 Redis(建议按 key 前缀分类,如
item:id:{id})
Spring 里常见做法:实现InitializingBean,在依赖注入完成后执行预热逻辑。
3.5 缓存同步:一致性三策略
常见三种:
- 设置 TTL:简单但时效差
- 同步双写:强一致但侵入代码、耦合高
- 异步通知:低耦合,允许短暂不一致(MQ / Canal)
基于 Canal 的优势:业务代码零侵入,通过订阅 MySQL binlog 触发缓存更新。
四、场景应用(用在哪里)
场景 1:高并发商品详情(多级缓存)
- 需求:页面高并发访问,Tomcat/DB 扛不住
- 方案:OpenResty 本地缓存(短TTL)+ Redis + Tomcat JVM 缓存(Caffeine)
- 收益:把大量读请求挡在更前面,减少 Tomcat 压力,DB 峰值更稳
场景 2:数据更新频繁(Canal 异步同步)
- 需求:商品价格/库存更新后,缓存尽快一致
- 方案:Canal 监听 binlog -> 通知缓存服务更新 Redis/JVM 缓存
- 收益:业务代码更干净,多个缓存服务可统一同步
五、开发避坑总结(高频错误)
5.1 BigKey:一定要治理
推荐阈值(经验值):
- 单个 key 的 value < 10KB
- 集合类型元素数量 < 1000
危害:
- 网络阻塞(少量 QPS 占满带宽)
- 数据倾斜(某节点内存爆)
- 主线程阻塞(集合运算耗时)
- CPU 压力(序列化/反序列化)
发现方式:
redis-cli -a 密码 --bigkeysSCAN+strlen/hlen/llen/scard/zcard自行统计- 分析 RDB(第三方工具)/ 网络监控
删除建议:
- Redis 4.0+ 优先
UNLINK异步删除,避免阻塞
5.2 Key 设计最佳实践
- 格式:
业务名:数据名:id - 简短:尽量不超过 44 字节(利于 embstr 编码与内存友好)
- 不要特殊字符
5.3 批处理优化:MSET vs Pipeline
瓶颈往往在网络往返,不在 Redis 执行本身:
MSET/HMSET:适合部分类型Pipeline:适合多命令批处理
集群下批处理:多 key 不同 slot 会失败,需要:
- 按 slot 分组(并行 slot 推荐)
- 或用 hash tag 强制落同 slot(但可能数据倾斜)
5.4 慢查询治理(Redis 单线程要警惕)
建议配置:
slowlog-log-slower-than:建议 1000 微秒(按业务调整)slowlog-max-len:建议 1000
常用命令:
SLOWLOG LENSLOWLOG GET [n]SLOWLOG RESET
5.5 安全加固(线上必做)
高危条件:
- Redis 未设密码
- 暴露公网
bind 0.0.0.0 - 允许
CONFIG SET - 使用 root 启动 Redis
建议:
- 必设密码
bind限制网卡 + 防火墙- 禁用危险命令(
rename-command):keys/flushall/flushdb/config set等 - 不要 root 运行,避免默认端口暴露
六、面试考点(能说出来)
6.1 高频问题
Q1:RDB 与 AOF 区别?
A:RDB 是快照,恢复快但可能丢窗口期数据;AOF 是追加日志,数据更完整但体积大,需要重写压缩。Q2:主从全量/增量同步如何判断?
A:看replid是否一致、offset 是否能在repl_backlog中找到;offset 被覆盖只能全量。Q3:Sentinel 如何判断下线?
A:单个 sentinel 超时未响应为主观下线;达到 quorum 多数认为下线为客观下线。Q4:Redis Cluster 为啥是 16384 slot?怎么路由 key?
A:对 key 有效部分做 CRC16,取余 16384 得 slot,slot 映射到节点。
6.2 进阶追问
- 集群下为什么 lua/事务麻烦? -> 原子性要求 key 在同一节点;跨节点无法保证。
- 为什么不建议大规模集群? -> 节点互 ping 带宽开销、兼容性问题、数据倾斜与客户端复杂度上升。
七、总结(复盘与下一步)
- 本文解决了:Redis 从“会用”到“能上生产”的关键能力拼图(高可用、扩展、性能体系、治理与安全)。
- 你现在可以:为业务选择主从/哨兵/集群方案,落地多级缓存,并具备线上排查与优化抓手。
本文为MY_TEUCK原创实战学习笔记,持续更新Java后端与AI应用领域干货,问题欢迎评论区交流。