黑马程序员Redis入门到实战教程 — 课程笔记
课程来源:B站黑马程序员,共175节,涵盖Redis从入门到原理的完整知识体系。本笔记按章节与知识点系统整理,适合Java开发者学习参考。
一、导学篇
本课程分为四大篇章,涵盖Redis的各种数据结构和命令、常见Java客户端应用、企业级实战方案(共享Session、缓存策略、分布式锁、消息队列、秒杀),以及Redis主从/哨兵/集群的搭建与原理,最后深入底层数据结构、网络模型、通信协议和内存淘汰策略。
二、基础篇
2.1 初识Redis
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 01-02 | 认识NoSQL | NoSQL概念、与关系型数据库对比、适用场景 |
| 03 | 认识Redis | Redis特性(高性能、持久化、丰富数据结构)、典型应用场景 |
| 04 | 安装Redis | Linux/Windows安装、三种启动方式(前台/后台/配置文件) |
| 05 | 命令行客户端 | redis-cli 基本使用、连接认证 |
| 06 | 图形化客户端 | Redis Desktop Manager 等GUI工具 |
知识点: - NoSQL四大分类:键值型(Redis)、文档型(MongoDB)、列族型(HBase)、图数据库(Neo4j) - Redis特点:基于内存、单线程(命令执行)、支持持久化、支持主从复制 - 三种启动方式:redis-server(前台)、redis-server &(后台)、redis-server /path/to/redis.conf(配置文件)
2.2 Redis数据结构与命令
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 07 | 数据结构介绍 | 五大基本类型概览 |
| 08 | 通用命令 | keys *、exists、del、expire、ttl、type |
| 09 | String类型 | set/get/mset/mget/incr/decr、缓存场景 |
| 10 | Key的层级格式 | user:1:name 命名规范 |
| 11 | Hash类型 | hset/hget/hmset/hgetall、对象存储场景 |
| 12 | List类型 | lpush/rpush/lpop/rpop/lrange、消息队列 |
| 13 | Set类型 | sadd/smembers/sinter/sunion、交集并集差集 |
| 14 | SortedSet类型 | zadd/zrange/zrank/zscore、排行榜场景 |
知识点: - String:最基础类型,可存储字符串/数值/二进制,最大512MB - Hash:适合存储对象,类似Java的HashMap - List:有序可重复,支持左右操作,可用作简单消息队列 - Set:无序不重复,支持集合运算(交并差) - SortedSet(ZSet):带分数的有序集合,天然排行榜
2.3 Redis的Java客户端
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 15 | 客户端对比 | Jedis vs Lettuce vs Redisson |
| 16-17 | Jedis | 快速入门、连接池配置 |
| 18 | SpringDataRedis | 简介、与SpringBoot整合 |
| 19-22 | RedisTemplate | 快速入门、序列化器、StringRedisTemplate、Hash操作 |
知识点: - Jedis:轻量直连Redis,线程不安全,需配合连接池 - Lettuce:基于Netty,线程安全,SpringBoot默认客户端 - Redisson:分布式对象和服务,内置分布式锁实现 - RedisTemplate:Spring封装,支持多种序列化方式(JDK/Jackson/String) - StringRedisTemplate:专门处理String类型的模板,key和value都用String序列化
三、实战篇
3.1 短信登录(Session管理)
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 02 | 导入黑马点评项目 | 项目结构、数据库设计 |
| 03-06 | 基于Session实现 | 发送验证码、登录注册、拦截器校验 |
| 07 | 隐藏敏感信息 | 用户信息脱敏 |
| 08-10 | Session共享问题 | 集群Session不一致 → Redis替代方案 |
| 11 | 登录状态刷新 | Token续期、滑动窗口 |
知识点: - Session问题:多服务器Session不共享、内存限制、无法持久化 - Redis替代Session:以Token为Key、用户信息为Value存入Redis - 拦截器方案:HandlerInterceptor + ThreadLocal传递用户信息 - Token续期:每次请求刷新过期时间(滑动窗口机制)
3.2 商户查询缓存
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 01 | 什么是缓存 | 缓存的作用、Cache Aside模式 |
| 02-03 | 添加商户缓存 | 查询时先查缓存、缓存未命中查DB |
| 04 | 缓存更新策略 | Cache Aside / Read/Write Through / Write Behind |
| 05 | 双写一致 | 先更新DB再删除缓存(延迟双删) |
| 06-07 | 缓存穿透 | 布隆过滤器 / 缓存空值 |
| 08 | 缓存雪崩 | TTL随机化 / 多级缓存 / 熔断降级 |
| 09-11 | 缓存击穿 | 互斥锁 / 逻辑过期 |
| 12-13 | 工具封装与总结 | 通用缓存工具类 |
知识点: - 缓存穿透:查询不存在的数据,每次都打到DB → 布隆过滤器拦截 or 缓存空值 - 缓存雪崩:大量Key同时过期 → TTL加随机值、多级缓存 - 缓存击穿:热Key过期瞬间高并发 → 互斥锁(SETNX)或逻辑过期(不设TTL,value内带过期时间) - 双写一致性:推荐”先更新DB,再删除缓存”;极端情况用延迟双删 - 逻辑过期方案:缓存永不过期,但value中包含过期时间字段,后台异步重建
3.3 优惠券秒杀
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 01-02 | 全局唯一ID | Redis INCR实现分布式ID生成 |
| 03-04 | 秒杀下单 | 库存扣减、订单创建 |
| 05-06 | 超卖问题 | 乐观锁(版本号/CAS)解决 |
| 07 | 一人一单 | 同用户限购一单 |
| 08 | 集群并发安全 | 分布式锁引入 |
知识点: - 全局唯一ID方案:时间戳 + Redis自增序列,格式:时间戳(32bit) + 序列号(32bit) - 超卖问题:UPDATE SET stock = stock - 1 WHERE id = ? AND stock > 0 乐观锁 - 一人一单:先查是否有未支付/已支付订单,使用分布式锁保证同一用户串行 - 集群安全:单机synchronized在集群下失效,需要分布式锁
3.4 分布式锁
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 09 | 基本原理 | 分布式锁的概念、实现方式对比(MySQL/Redis/ZooKeeper) |
| 10-11 | Redis实现V1 | SET lock_key unique_value NX EX |
| 12-13 | 误删问题 | 锁标识校验、释放前检查持有者 |
| 14-16 | 原子性问题 | Lua脚本保证”判断+释放”原子性 |
| 17-18 | Redisson入门 | Redisson特性、快速集成 |
| 19-21 | Redisson原理 | 可重入锁(Hash结构)、WatchDog自动续期、MultiLock联锁 |
知识点: - 基础分布式锁:SET key value NX EX seconds,释放时用Lua脚本先比较value再删除 - 误删问题:线程A锁过期被释放 → 线程B获取锁 → A删除了B的锁 → 解决:释放前校验value - 原子性问题:判断和删除非原子 → Lua脚本封装 - Redisson可重入锁:Hash结构存储 lockName → threadId → count,同线程可重入计数 - WatchDog机制:默认30秒过期,后台每10秒续期(1/3过期时间) - MultiLock:多个Redis节点同时加锁,全部成功才算获取锁(提高可用性)
3.5 秒杀优化
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 22 | 异步秒杀思路 | 同步阻塞 → 异步队列 |
| 23 | Redis资格判断 | 库存预扣减、用户校验在Redis中完成 |
| 24 | 阻塞队列下单 | 内存阻塞队列 → 异步写入DB |
知识点: - 异步秒杀流程:用户请求 → Redis判断资格(库存+一人一单)→ 合格则加入阻塞队列 → 后台线程异步创建订单 - 优势:将同步IO操作(DB写入)转为异步,大幅提高吞吐量 - 库存预扣减:用Lua脚本原子执行 decr stock + sadd order_set userId
3.6 Redis消息队列
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 25 | 认识消息队列 | 消息队列概念、主流方案对比 |
| 26 | List实现 | LPUSH+BRPOP阻塞消费 |
| 27 | PubSub实现 | 发布订阅模式 |
| 28-29 | Stream | 单消费者模式、消费者组模式 |
| 30 | Stream实现异步秒杀 | 基于Stream消费者组的完整方案 |
知识点: - List消息队列:简单但不支持消费者组,消息可能丢失 - PubSub:支持多消费者但不支持持久化,消费者离线消息丢失 - Stream:Redis 5.0+,支持消费者组、消息确认(ACK)、消息持久化 - 消费者组:XREADGROUP GROUP group_name consumer_name COUNT n STREAMS key > - 异步秒杀升级:阻塞队列 → Stream消费者组,支持多实例消费
3.7 达人探店
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 01-02 | 探店笔记 | 发布/查看笔记 |
| 03-04 | 点赞功能 | SortedSet实现点赞排行榜 |
知识点: - 点赞排行:ZADD blog:likes:blogId score userId,按时间戳排序 - TopN查询:ZREVRANGE blog:likes:blogId 0 9 WITHSCORES - 去重点赞:同一用户对同一笔记只能点赞一次
3.8 好友关注与Feed流
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 05-06 | 关注/取关/共同关注 | Set集合运算 SINTER |
| 07-10 | Feed流 | 推模式 vs 拉模式 vs 推拉结合、滚动分页 |
知识点: - 共同关注:SINTER user:follows:user1 user:follows:user2 - Feed流三种模式: - 推模式:发布者发帖时推送到所有粉丝收件箱(写扩散) - 拉模式:粉丝读取时聚合关注者列表的帖子(读扩散) - 推拉结合:大V用拉模式,普通用户用推模式 - 滚动分页:基于SortedSet的 ZREVRANGEBYSCORE + LIMIT offset count
3.9 附近商铺(GEO)
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 11 | GEO基本用法 | GEOADD/GEODIST/GEOSEARCH |
| 12-13 | 实现附近商户 | 导入数据 + 查询实现 |
知识点: - 底层结构:GEO基于SortedSet实现,score是geohash编码 - 核心命令:GEOADD key longitude latitude member、GEOSEARCH key FROMLONLAT lng lat BYRADIUS r KM - 应用场景:附近商户、签到定位
3.10 用户签到(BitMap)
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 15 | BitMap演示 | SETBIT/GETBIT/BITCOUNT/BITPOS |
| 16-17 | 签到功能 | 连续签到统计 |
知识点: - BitMap:用bit位表示状态,极大节省内存 - 签到实现:SETBIT sign:userId:202603 offset dayOfMonth 1 - 连续签到统计:BITCOUNT sign:userId:202603 + BITPOS 查找连续1的个数 - 内存效率:一年365天只需约46字节
3.11 UV统计(HyperLogLog)
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 18 | HyperLogLog用法 | PFADD/PFCOUNT/PFMERGE |
| 19 | 百万数据测试 | 误差率测试 |
知识点: - HyperLogLog:基数统计算法,占用固定12KB内存,误差率约0.81% - 命令:PFADD key element 添加、PFCOUNT key 统计 - 适用场景:UV统计(独立访客数)、百万/千万级数据去重计数
四、高级篇
4.1 分布式缓存(持久化 + 集群)
4.1.1 Redis持久化
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 02-03 | RDB | bgsave、fork原理、COW(Copy-On-Write) |
| 04 | AOF | Append Only File、三种刷盘策略 |
| 05 | RDB vs AOF | 优缺点对比、混合持久化 |
知识点: - RDB(快照):bgsave触发fork子进程,COW机制保证父进程继续服务 - AOF(追加日志):记录每条写命令,always/everysec/no三种策略 - RDB优缺点:恢复快、文件紧凑,但可能丢失较多数据 - AOF优缺点:数据安全性高,但文件大、恢复慢 - 混合持久化:RDB+AOF,AOF文件头部是RDB格式
4.1.2 Redis主从
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 06-07 | 主从集群 | 结构介绍、搭建方法 |
| 08 | 全量同步 | 第一次同步流程(RDB传输) |
| 09 | 增量同步 | REPLICAOF、PSYNC、repl_backlog |
知识点: - 全量同步:从节点发送 SYNC → 主节点 bgsave + 发送RDB → 从节点加载 → 后续命令同步 - 增量同步:基于 repl_backlog_buffer(环形缓冲区),从节点断线重连后继续同步 - 关键配置:replicaof <masterip> <masterport>、repl-backlog-size
4.1.3 Redis哨兵(Sentinel)
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 10 | 哨兵原理 | 监控、通知、自动故障转移 |
| 11 | 搭建哨兵集群 | 哨兵配置、最少3个节点 |
| 12 | RedisTemplate连接 | Sentinel连接配置 |
知识点: - 哨兵职责:监控主从状态、自动故障转移、通知客户端 - 主观下线:单个哨兵认为Master不可用 - 客观下线:多数哨兵认为Master不可用 → 触发故障转移 - 选举新Master:优先级 > 复制偏移量 > RunID
4.1.4 Redis分片集群
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 13-14 | 分片集群 | 搭建、16384个哈希槽 |
| 15-16 | 集群管理 | 伸缩操作、故障转移 |
| 17 | Java访问 | RedisTemplate分片集群配置 |
知识点: - 哈希槽:16384个槽位,Key通过 CRC16(key) % 16384 映射到槽位 - 数据分布:每个节点负责一部分槽位 - 重定向:MOVED(永久重定向)/ ASK(临时重定向) - 批量操作限制:MGET/MSET的Key必须在同一节点(同一slot)
4.2 多级缓存
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 01 | 多级缓存架构 | 浏览器 → Nginx → JVM → Redis → DB |
| 02-05 | JVM进程缓存 | Caffeine本地缓存入门和实现 |
| 06-08 | Lua语法 | 变量、循环、函数、条件控制 |
| 09-17 | OpenResty | 安装、入门、Nginx本地缓存、Redis查询、负载均衡 |
| 18-20 | 缓存同步 | 数据同步策略、Canal监听MySQL binlog |
知识点: - Caffeine:高性能Java本地缓存,W-TinyLFU淘汰算法 - OpenResty:基于Nginx + Lua的高性能Web平台 - 多级缓存流程:请求 → Nginx本地缓存 → Redis → Tomcat → DB - Canal:监听MySQL binlog,数据变更时同步更新各级缓存 - 缓存同步策略:设置Canal监听,当DB数据变化时自动清理/更新Redis和Nginx缓存
4.3 Redis最佳实践
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 02-04 | 键值设计 | 优雅的Key命名、BigKey问题、选择合适数据结构 |
| 05-06 | 批处理优化 | Pipeline、MSET、集群下的批处理 |
| 07-10 | 服务端优化 | 持久化配置、慢查询、命令安全、内存管理 |
| 11 | 架构选择 | 集群 vs 主从,选型建议 |
知识点: - Key设计规范:业务名:表名:id,如 heima:shop:1 - BigKey:单个Key的value过大(如超过10KB的String、超过5000个元素的Hash/Set),影响网络和内存 - Pipeline:批量发送命令,减少RTT,但不保证原子性 - 慢查询:slowlog get 查看,slowlog-log-slower-than 设置阈值(默认10ms) - 内存淘汰:推荐 allkeys-lru 或 volatile-lru
五、原理篇
5.1 Redis底层数据结构
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 02 | 动态字符串(SDS) | 结构体、与C字符串对比、预分配/惰性释放 |
| 03 | IntSet | 整数集合、升级机制 |
| 04-05 | Dict | 哈希表、渐进式rehash |
| 06-07 | ZipList | 压缩列表、连锁更新问题 |
| 08 | QuickList | 双向链表 + ZipList组合 |
| 09 | SkipList | 跳表结构、多层索引 |
| 10 | RedisObject | 统一对象系统、type + encoding |
知识点: - SDS:带长度的字符串,O(1)获取长度、防止缓冲区溢出、二进制安全 - IntSet:有序整数数组,支持升级(int16 → int32 → int64),节省内存 - Dict:双哈希表结构,渐进式rehash避免一次性扩容阻塞 - ZipList:连续内存紧凑存储,节省指针开销,但连锁更新导致最坏O(n²) - QuickList:LinkedList + ZipList,每个节点是一个ZipList,平衡紧凑和性能 - SkipList:多层有序链表,平均O(logN)查找,Redis用它实现ZSet - RedisObject:统一包装,type(5种类型)+ encoding(底层编码)+ ptr(数据指针)
5.2 五种数据类型的底层编码
| 数据类型 | 底层编码 | 转换条件 |
|---|---|---|
| String | int / embstr / raw | int可直接存储则用int,≤44字节用embstr |
| List | LinkedList / ZipList / QuickList | Redis 3.2+ 默认QuickList |
| Set | IntSet / HashTable | 全为整数且≤512用IntSet |
| ZSet | ZipList / SkipList + Dict | 元素≤128且长度≤64用ZipList |
| Hash | ZipList / HashTable | 字段≤128且值≤64字节用ZipList |
5.3 Redis网络模型
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 16-18 | IO基础 | 用户/内核空间、阻塞IO、非阻塞IO |
| 19-24 | IO多路复用 | select/poll/epoll、ET/LT模式、服务端流程 |
| 25-27 | 线程模型 | 信号驱动IO、Redis单线程原因、6.0多线程网络IO |
| 28-29 | RESP协议 | 协议格式、手写Redis客户端 |
| 30-31 | 内存管理 | 过期Key删除策略、内存淘汰策略 |
知识点: - IO多路复用:一个线程监听多个文件描述符,epoll基于事件驱动 - epoll:epoll_create → epoll_ctl(注册事件)→ epoll_wait(等待事件) - ET vs LT:ET(边缘触发)只通知一次需一次读完;LT(水平触发)反复通知 - Redis单线程:命令执行单线程,避免上下文切换和锁竞争;6.0+网络IO多线程 - RESP协议:简单文本协议,+OK\r\n、-ERR\r\n、:100\r\n、$5\r\nhello\r\n、*2\r\n...
5.4 内存回收
| 节次 | 主题 | 核心内容 |
|---|---|---|
| 30 | 过期Key处理 | 惰性删除 + 定期删除 |
| 31 | 内存淘汰策略 | 8种淘汰策略详解 |
知识点: - 过期删除:惰性删除(访问时检查)+ 定期删除(定时任务采样) - 淘汰策略: - noeviction:不淘汰,写满返回错误 - volatile-lru:从有过期时间的Key中淘汰最近最少使用 - allkeys-lru:从所有Key中淘汰LRU(推荐) - volatile-ttl:淘汰即将过期的Key - volatile-random:随机淘汰有过期时间的Key - allkeys-random:随机淘汰所有Key - volatile-lfu:从有过期时间的Key中淘汰最不常使用 - allkeys-lfu:从所有Key中淘汰LFU(Redis 4.0+)
六、课程总结
本课程从Redis基础命令出发,逐步深入到企业级实战场景(短信登录、缓存、秒杀、分布式锁、消息队列、社交功能、附近商户、签到统计),再进入高级架构(持久化、主从、哨兵、分片集群、多级缓存),最后深入底层原理(数据结构、网络模型、内存管理)。是一套完整的Redis学习路线,适合Java开发者系统掌握Redis在企业中的应用。
参考资料: - Redis官方文档 - Redis命令参考 - B站黑马程序员Redis课程