Redis 核心技术与实战
Redis 是一款高性能的键值数据库,广泛应用于缓存、消息队列、排行榜、分布式锁等场景。掌握 Redis 的核心原理和实战技巧是后端开发工程师的必备技能。
本站 Redis 导航
建议阅读顺序:基础数据类型 → 底层数据结构 → 持久化 → 缓存策略 → 集群架构 → 分布式锁 → 性能优化 → 应用场景。
- Redis数据类型与底层实现:String/Hash/List/Set/ZSet 五大类型,SDS/ziplist/skiplist/intset/dict 底层实现,编码转换规则
- Redis持久化机制:RDB 快照原理、AOF 日志机制、混合持久化策略、持久化配置调优
- Redis缓存策略:缓存穿透/击穿/雪崩解决方案、缓存更新策略(旁路/直写/异步刷新)、布隆过滤器实战
- Redis集群方案:主从复制原理、哨兵选举机制、Cluster 分片与槽位、一致性哈希、扩缩容流程
- Redis分布式锁:基于 SETNX 实现、Redisson 分布式锁、Redlock 算法、锁续期与看门狗机制
- Redis-性能优化:Pipeline 批量操作、大 key 与热 key 处理、内存淘汰策略、慢查询分析、Redis 多线程模型
- Redis应用场景实战:排行榜(ZSet)、消息队列(Stream)、限流(漏桶/令牌桶)、分布式 ID、地理位置、会话共享
下面是 Redis 知识体系的完整学习路径:
Redis 学习大纲
第一阶段:数据类型与核心命令
五大基础数据类型:
- String (字符串):
- 应用场景:缓存、计数器、分布式锁、Session 共享。
- 核心命令:
SET,GET,INCR,DECR,SETEX,SETNX。 - 底层实现:SDS (Simple Dynamic String),预分配空间、杜绝缓冲区溢出。
- Hash (哈希):
- 应用场景:存储对象(如用户信息)。
- 核心命令:
HSET,HGET,HMGET,HINCRBY。 - 底层实现:ziplist(元素少时)或 dict(元素多时)。
- List (列表):
- 应用场景:消息队列、文章列表、最新消息。
- 核心命令:
LPUSH,RPUSH,LPOP,RPOP,LRANGE,BLPOP。 - 底层实现:quicklist(双向链表 + ziplist 的混合体)。
- Set (集合):
- 应用场景:标签系统、共同好友、去重。
- 核心命令:
SADD,SMEMBERS,SINTER,SUNION,SISMEMBER。 - 底层实现:intset(整数集合)或 dict。
- ZSet (有序集合):
- 应用场景:排行榜、延时队列、范围查询。
- 核心命令:
ZADD,ZRANGE,ZREVRANGE,ZRANK,ZINCRBY。 - 底层实现:ziplist 或 skiplist + dict。
- String (字符串):
三种特殊数据类型:
- Bitmap (位图): 布隆过滤器、签到统计。
- HyperLogLog: 基数统计(UV 统计)。
- Geospatial (地理位置): 附近的人、打车距离。
- Stream (流): 消息队列(Redis 5.0+)。
第二阶段:底层数据结构深入
SDS (Simple Dynamic String):
- 与 C 字符串的区别:
len记录长度、free预分配空间、二进制安全。 - 为什么 Redis 的 String 不用原生 C 字符串?避免溢出、减少内存分配次数。
- 与 C 字符串的区别:
ziplist (压缩列表):
- 紧凑型数据结构,节省内存。
- 缺点:连锁更新(cascading update)性能问题。
- 应用:Hash、List、ZSet 在元素少时使用。
skiplist (跳表):
- 有序数据结构,平均 O(log N) 复杂度。
- ZSet 的核心实现(配合 dict 实现 O(1) 查找)。
- 与红黑树对比:实现简单、范围查询友好。
dict (字典/哈希表):
- 渐进式 rehash:避免一次性 rehash 阻塞。
- 链地址法解决哈希冲突。
- 应用:Hash、Set、ZSet、Redis 全局键空间。
intset (整数集合):
- Set 在全是整数且数量少时使用。
- 升级机制:从 int16 -> int32 -> int64。
quicklist:
- List 的底层实现(Redis 3.2+)。
- 双向链表 + ziplist 的混合体,平衡内存与性能。
第三阶段:持久化机制
RDB (Redis Database Backup):
- 全量快照,适合备份和恢复。
- 触发方式:
SAVE(阻塞)、BGSAVE(fork 子进程)、自动触发(配置save规则)。 - 优点:恢复速度快、文件体积小。
- 缺点:数据丢失风险(快照间隔内的数据会丢失)。
AOF (Append Only File):
- 增量日志,记录每条写命令。
- 刷盘策略:
always(每条命令)、everysec(每秒)、no(操作系统决定)。 - AOF 重写(rewrite):压缩日志文件,减少体积。
- 优点:数据丢失少、可读性强。
- 缺点:文件体积大、恢复速度慢。
混合持久化(RDB + AOF):
- Redis 4.0+ 默认策略。
- AOF 重写时,先生成 RDB 快照,再追加增量命令。
- 兼具两者优点:恢复快、数据丢失少。
第四阶段:缓存策略与高可用
缓存更新策略:
- Cache Aside(旁路缓存): 读穿透缓存、更新先删缓存再写 DB。
- Read/Write Through: 缓存层自动同步 DB。
- Write Behind(异步刷新): 先写缓存,异步批量写 DB。
缓存失效问题:
- 缓存穿透: 查询不存在的数据。
- 解决:布隆过滤器、缓存空对象。
- 缓存击穿: 热点 key 过期,瞬时流量打到 DB。
- 解决:互斥锁(SETNX)、逻辑过期(永不过期 + 异步更新)。
- 缓存雪崩: 大量 key 同时过期。
- 解决:随机过期时间、高可用架构、限流降级。
- 缓存穿透: 查询不存在的数据。
内存淘汰策略:
noeviction:内存满时拒绝写入。allkeys-lru:所有 key 按 LRU 淘汰(推荐)。volatile-lru:仅淘汰设置了过期时间的 key。allkeys-random、volatile-random、volatile-ttl。
第五阶段:集群架构
主从复制 (Replication):
- 全量同步(RDB)+ 增量同步(命令传播)。
- 读写分离:主节点写、从节点读。
- 缺点:主节点宕机需手动切换。
哨兵模式 (Sentinel):
- 自动故障转移(Failover)。
- 选举新的主节点(Raft 协议)。
- 监控 + 通知 + 自动切换。
Cluster (集群):
- 数据分片:16384 个哈希槽(slot)。
- 去中心化架构,无 Proxy 层。
- 扩缩容:槽位迁移(
redis-cli --cluster reshard)。 - Gossip 协议:节点间通信。
第六阶段:分布式锁与事务
分布式锁:
- 基础实现:
SETNX+EXPIRE(需原子性:SET key value NX EX seconds)。 - Redisson 分布式锁:自动续期(看门狗机制)。
- Redlock 算法:Redis 作者提出的多节点锁方案(争议较大)。
- 基础实现:
事务与 Lua 脚本:
- MULTI/EXEC: 事务不支持回滚,仅保证命令顺序执行。
- WATCH: 乐观锁,监控 key 变化。
- Lua 脚本: 原子性执行一组命令(推荐方式)。
Pipeline(管道):
- 批量发送命令,减少 RTT(Round-Trip Time)。
- 非原子操作,与事务结合使用可保证原子性。
第七阶段:性能优化与监控
性能调优:
- 大 key 问题: 使用
redis-cli --bigkeys分析,拆分大 key。 - 热 key 问题: 复制多份、使用本地缓存(Caffeine)。
- 慢查询:
SLOWLOG GET分析慢命令。 - Redis 多线程模型: Redis 6.0+ 网络 I/O 多线程(命令执行仍单线程)。
- 大 key 问题: 使用
监控工具:
INFO命令:查看内存、连接、持久化等信息。MONITOR:实时查看所有命令(生产慎用,性能影响大)。- Redis Exporter + Prometheus + Grafana:企业级监控方案。
第八阶段:应用场景实战
- 排行榜: ZSet 的
ZADD+ZREVRANGE。 - 消息队列: List 的
BLPOP/BRPOP或 Stream(推荐)。 - 限流:
- 固定窗口:
INCR+EXPIRE。 - 滑动窗口:ZSet 时间戳。
- 令牌桶/漏桶:Lua 脚本 + 原子操作。
- 固定窗口:
- 分布式 ID 生成:
INCR单机递增、雪花算法。 - 会话共享: Spring Session + Redis。
- 地理位置:
GEOADD、GEORADIUS查找附近的人。 - 布隆过滤器: Redisson 实现、缓存穿透防护。
学习建议
从实战出发:
- 先掌握常用命令和应用场景,再深入底层原理。
- 通过
redis-cli命令行实践每个数据类型。
源码阅读路径:
- 先看数据结构源码(如
sds.c、dict.c)。 - 再看持久化(
rdb.c、aof.c)。 - 最后看集群实现(
cluster.c)。
- 先看数据结构源码(如
调试与压测:
- 使用
redis-benchmark压测性能。 - 通过
INFO MEMORY分析内存使用。 - 使用 Docker 搭建本地 Redis Cluster 环境。
- 使用
面试准备:
- 熟练掌握”三高”问题(穿透、击穿、雪崩)。
- 理解持久化原理与选型(RDB vs AOF)。
- 掌握分布式锁实现与坑点(锁过期、死锁)。
持续学习:
- 关注 Redis 官方博客和社区动态。
- 阅读《Redis 设计与实现》(黄健宏)。
- 学习企业级架构(如阿里云 Redis、AWS ElastiCache)。
核心知识点速查
1. 数据类型与底层编码对应关系
| 类型 | 底层编码(encoding) | 转换条件 |
|---|---|---|
| String | int / embstr / raw | 整数/短字符串(<44 字节)/长字符串 |
| Hash | ziplist / hashtable | 元素少且值小 → ziplist,否则 hashtable |
| List | quicklist(ziplist + linkedlist) | Redis 3.2+ 统一使用 quicklist |
| Set | intset / hashtable | 全是整数且少 → intset,否则 hashtable |
| ZSet | ziplist / skiplist + hashtable | 元素少且值小 → ziplist,否则 skiplist+dict |
2. 持久化对比表
| 特性 | RDB | AOF | 混合持久化(RDB+AOF) |
|---|---|---|---|
| 文件大小 | 小(压缩二进制) | 大(文本日志) | 中等(前半部分 RDB,后半增量) |
| 恢复速度 | 快 | 慢 | 快(先加载 RDB) |
| 数据丢失 | 多(快照间隔内数据会丢) | 少(可配置每秒刷盘) | 少 |
| 性能影响 | fork 时有短暂阻塞 | 持续追加写,影响较小 | fork + 追加 |
| 适用场景 | 备份、冷数据、对丢失不敏感场景 | 金融、订单等高数据一致性场景 | 生产环境推荐(默认策略) |
3. 主从复制 vs 哨兵 vs Cluster
| 架构 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 主从复制 | 简单、读写分离 | 手动故障转移、写能力受限 | 小规模、读多写少 |
| 哨兵 | 自动故障转移、高可用 | 写能力仍受限、运维复杂度提升 | 中等规模、需高可用 |
| Cluster | 数据分片、水平扩展、去中心化 | 配置复杂、不支持跨节点事务、运维成本高 | 大规模、高并发、需分片 |
4. 内存淘汰策略速查
| 策略 | 淘汰范围 | 淘汰算法 | 推荐场景 |
|---|---|---|---|
| noeviction | - | - | 不允许淘汰,写入报错 |
| allkeys-lru | 所有 key | LRU | 通用场景(推荐) |
| volatile-lru | 设置过期时间的 key | LRU | 部分数据需永久保留 |
| allkeys-random | 所有 key | 随机 | 测试环境 |
| volatile-random | 设置过期时间的 key | 随机 | 不推荐 |
| volatile-ttl | 设置过期时间的 key | 优先淘汰 TTL 短 | Session、验证码等短期数据 |
面试题 / Checklist
- Redis 为什么快?单线程模型、IO 多路复用、内存操作、高效数据结构。
- String 的三种编码(int/embstr/raw)分别在什么场景下使用?
- skiplist 的平均时间复杂度是多少?为什么 ZSet 不用红黑树?
- 渐进式 rehash 如何避免阻塞?在 rehash 期间如何查询和插入数据?
- RDB 和 AOF 的区别?混合持久化如何工作?生产环境如何选择?
- 缓存穿透/击穿/雪崩的本质区别与解决方案?
- 布隆过滤器的原理与误判率如何权衡?
- 分布式锁的实现方式?如何解决锁过期问题(Redisson 看门狗)?
- Redis Cluster 的哈希槽(16384)分配原理?节点间如何通信(Gossip)?
- 大 key 和热 key 如何发现与处理?
- Redis 6.0 的多线程是指什么?为什么命令执行仍是单线程?
- Pipeline、事务(MULTI/EXEC)、Lua 脚本三者的区别与适用场景?
- 如何保证缓存与数据库的一致性?先删缓存还是先更新 DB?
- Redis 内存淘汰策略 allkeys-lru 和 volatile-lru 的区别?
- Stream 数据类型相比 List 做消息队列的优势是什么?
祝你学习顺利!Redis 是高并发系统的核心组件,掌握它将大大提升你的系统设计能力!🚀
