Redis从入门到精通:入门到精通(万字详解)

目录

​编辑Redis学习路线:从入门到精通完全指南

[一、Redis 简介:为什么它如此重要?](#一、Redis 简介:为什么它如此重要?)

[1.1 什么是 Redis?](#1.1 什么是 Redis?)

[1.2 为什么大家都爱用 Redis?](#1.2 为什么大家都爱用 Redis?)

[1.2.1 快得离谱](#1.2.1 快得离谱)

[1.2.2 不仅仅是 String](#1.2.2 不仅仅是 String)

[1.2.3 多面手](#1.2.3 多面手)

[二、Redis 系统化学习路线(从入门到深入)](#二、Redis 系统化学习路线(从入门到深入))

第一阶段:初窥门径(基础与使用)

[2.1 环境搭建](#2.1 环境搭建)

[2.2 五大基础数据类型](#2.2 五大基础数据类型)

[2.2.1 String(字符串):最基础的万能贴纸](#2.2.1 String(字符串):最基础的万能贴纸)

[2.2.2 Hash(哈希):专属的档案袋](#2.2.2 Hash(哈希):专属的档案袋)

[2.2.3 List(列表):排队的长龙](#2.2.3 List(列表):排队的长龙)

[2.2.4 Set(集合):朋友圈的"圈子"](#2.2.4 Set(集合):朋友圈的"圈子")

[2.2.5 ZSet(Sorted Set / 有序集合):金牌排行榜](#2.2.5 ZSet(Sorted Set / 有序集合):金牌排行榜)

[2.3 通用命令](#2.3 通用命令)

[2.4 第一阶段小结](#2.4 第一阶段小结)

第三阶段:登堂入室(核心进阶功能)

[3.1 持久化机制(重点)](#3.1 持久化机制(重点))

[3.1.1 RDB(Redis Database):给内存拍一张"全景快照"](#3.1.1 RDB(Redis Database):给内存拍一张"全景快照")

[3.1.2 AOF(Append Only File):事无巨细的"流水账本"](#3.1.2 AOF(Append Only File):事无巨细的"流水账本")

[3.1.3 RDB 与 AOF 核心对比](#3.1.3 RDB 与 AOF 核心对比)

[3.1.4 终极杀手锏:RDB + AOF 混合持久化](#3.1.4 终极杀手锏:RDB + AOF 混合持久化)

[3.2 内存管理与淘汰策略](#3.2 内存管理与淘汰策略)

[3.2.1 过期(Expiration)与淘汰(Eviction)的区别](#3.2.1 过期(Expiration)与淘汰(Eviction)的区别)

[3.2.2 核心算法:LRU vs LFU](#3.2.2 核心算法:LRU vs LFU)

[3.2.3 Redis 的 8 种内存淘汰策略](#3.2.3 Redis 的 8 种内存淘汰策略)

[3.2.4 实战:我该怎么选?](#3.2.4 实战:我该怎么选?)

[3.3 事务与 Pipeline](#3.3 事务与 Pipeline)

[3.3.1 Pipeline(流水线):极致的"快递打包"艺术](#3.3.1 Pipeline(流水线):极致的"快递打包"艺术)

[3.3.2 Redis 事务(MULTI / EXEC):排队打饭的"一锤子买卖"](#3.3.2 Redis 事务(MULTI / EXEC):排队打饭的"一锤子买卖")

[3.3.3 为什么说 Redis 事务"不支持强一致性的回滚"?](#3.3.3 为什么说 Redis 事务"不支持强一致性的回滚"?)

[3.3.4 终极护盾:WATCH(乐观锁)](#3.3.4 终极护盾:WATCH(乐观锁))

[3.3.5 总结对比:该用哪个?](#3.3.5 总结对比:该用哪个?)

第四阶段:融会贯通(高并发与高可用架构)

[4.1 主从复制(Replication)](#4.1 主从复制(Replication))

[4.2 哨兵模式(Sentinel)](#4.2 哨兵模式(Sentinel))

[4.3 分片集群(Cluster)](#4.3 分片集群(Cluster))

[4.4 架构演进总结表](#4.4 架构演进总结表)

第五阶段:深不可测(底层原理与生产实战)

[5.1 缓存三大经典问题及解决方案](#5.1 缓存三大经典问题及解决方案)

[5.1.1 缓存穿透(Cache Penetration):查无此人的"夺命连环 Call"](#5.1.1 缓存穿透(Cache Penetration):查无此人的"夺命连环 Call")

[5.1.2 缓存击穿(Cache Breakdown):单点爆破的"巨星陨落"](#5.1.2 缓存击穿(Cache Breakdown):单点爆破的"巨星陨落")

[5.1.3 缓存雪崩(Cache Avalanche):集体大罢工的"末日灾难"](#5.1.3 缓存雪崩(Cache Avalanche):集体大罢工的"末日灾难")

[5.1.4 核心总结一张表](#5.1.4 核心总结一张表)

[5.2 Lua 脚本:真正的"绝对防御"](#5.2 Lua 脚本:真正的"绝对防御")

[5.2.1 为什么原生事务搞不定"秒杀"?(痛点回顾)](#5.2.1 为什么原生事务搞不定"秒杀"?(痛点回顾))

[5.2.2 Lua 脚本是什么?](#5.2.2 Lua 脚本是什么?)

[5.2.3 实战:一段完美的秒杀扣库存代码](#5.2.3 实战:一段完美的秒杀扣库存代码)

[5.2.4 现实世界的忠告:Lua 是把双刃剑](#5.2.4 现实世界的忠告:Lua 是把双刃剑)

[5.3 分布式锁:从单机思维跨越到分布式架构](#5.3 分布式锁:从单机思维跨越到分布式架构)

[5.3.1 什么是分布式锁?(一个抢厕所的比喻)](#5.3.1 什么是分布式锁?(一个抢厕所的比喻))

[5.3.2 Redis 原生分布式锁的"进化史"](#5.3.2 Redis 原生分布式锁的"进化史")

[5.3.3 Redisson 与它的"看门狗"(Watchdog)魔法](#5.3.3 Redisson 与它的"看门狗"(Watchdog)魔法)

[5.3.4 小结:分布式锁的三大铁律](#5.3.4 小结:分布式锁的三大铁律)

六、大厂面试实战模拟

[6.1 第一面:缓存架构场景题(防不住就背锅)](#6.1 第一面:缓存架构场景题(防不住就背锅))

[6.2 第二面:底层机制原理题(懂机制才能救火)](#6.2 第二面:底层机制原理题(懂机制才能救火))

[6.3 第三面:分布式锁高阶实战题(写错就发错钱)](#6.3 第三面:分布式锁高阶实战题(写错就发错钱))

七、总结与展望

[7.1 完整知识图谱回顾](#7.1 完整知识图谱回顾)

[7.2 学习建议](#7.2 学习建议)

[7.3 进阶方向](#7.3 进阶方向)

八、结语


Redis学习路线:从入门到精通完全指南

本文基于系统化学习Redis的完整路径,从基础概念到高阶架构,从单机部署到分布式集群,为你呈现一份详尽的Redis学习指南。无论你是刚接触Redis的新手,还是希望深入底层原理的进阶开发者,这篇文章都将帮助你建立完整的Redis知识体系。

一、Redis 简介:为什么它如此重要?

1.1 什么是 Redis?

Redis(Remote Dictionary Server) 是一个开源的、基于内存的键值对(Key-Value)数据结构存储系统。你可以把它想象成一个极其庞大且超级快的"字典"。通常的数据库(如 MySQL)是把数据存放在硬盘上的,而 Redis 把数据全都放在内存里。

Redis 是目前后端开发中最不可或缺的技术之一,无论你是做后端开发、系统架构还是应对性能优化,它都是一项"杀手锏"级别的技能。

1.2 为什么大家都爱用 Redis?

Redis 之所以如此受欢迎,主要有以下几个核心优势:

1.2.1 快得离谱

因为数据都在内存中,它的读写速度极快,单机轻松能达到每秒十万级别的并发读写。这种性能是传统磁盘数据库难以企及的。

1.2.2 不仅仅是 String

传统的缓存可能只能存字符串,但 Redis 支持非常丰富的数据结构,比如列表(List)、集合(Set)、哈希表(Hash)、有序集合(Sorted Set)等。这些数据结构让 Redis 能够应对各种复杂的业务场景。

1.2.3 多面手

它不仅能当缓存用(最常见的场景),还能当数据库、消息队列(Pub/Sub)、分布式锁等。这种多功能性使得 Redis 成为技术栈中不可或缺的一环。

二、Redis 系统化学习路线(从入门到深入)

为了让你不迷路,我们将 Redis 的学习分为四个阶段。我们可以一步一步来打通关:

第一阶段:初窥门径(基础与使用)

这个阶段的目标是:知道怎么把 Redis 跑起来,并且能熟练使用它最核心的"五种武器"。

2.1 环境搭建

在本地(Windows/Mac/Linux 或 Docker)安装并启动 Redis,连接 Redis 客户端(如 redis-cli 或可视化工具如 Another Redis Desktop Manager)。

2.2 五大基础数据类型

掌握了这五大基础数据类型,你就能应对日常开发中 80% 以上的 Redis 使用场景了。为了让你更容易理解,我们把 Redis 想象成一个"万能百宝箱"。

2.2.1 String(字符串):最基础的万能贴纸

这是 Redis 中最简单的数据类型。你可以把它想象成一张便利贴,上面写着一个名字(Key)和对应的一段话或数字(Value)。虽然叫"字符串",但它其实也可以存数字,甚至是一张图片的二进制数据。

生活化场景:文章阅读量计数器。每次有人点开文章,阅读量就加 1;或者手机验证码,发送后要求 5 分钟内有效。

命令演示:

java 复制代码
# 场景 1:缓存一个验证码,并设置 60 秒后过期(EX:seconds)
SET user:1001:code "849201" EX 60

# 获取这个验证码
GET user:1001:code
# 返回:"849201"

# 场景 2:文章阅读量点赞计数
SET article:99:views 0

# 每当有人阅读,就让它自增 1
INCR article:99:views
# 返回:1

INCR article:99:views
# 返回:2
2.2.2 Hash(哈希):专属的档案袋

Hash 特别像一个档案袋或者编程语言里的对象(Object/JSON)。一个大 Key 对应着一个档案袋,里面可以装多个属性(字段 Field)和对应的值(Value)。

生活化场景:存储用户的个人资料(比如姓名、年龄、粉丝数)。如果用 String 存,你可能要把整个用户信息打包成一个长字符串;但用 Hash,你可以单独修改某一个属性,比如只修改他的粉丝数,而不影响其他信息。

命令演示:

java 复制代码
# 把用户张三的信息存入档案袋(Key 为 user:1001)
HSET user:1001 name "ZhangSan" age 25 fans 100

# 单独获取张三的名字
HGET user:1001 name
# 返回:"ZhangSan"

# 张三涨粉了,给他的粉丝数加 1
HINCRBY user:1001 fans 1
# 返回:101

# 一次性查看张三的所有档案信息
HGETALL user:1001
# 返回:name, ZhangSan, age, 25, fans, 101
2.2.3 List(列表):排队的长龙

List 就是一个按顺序排列的字符串队伍。你可以从队伍的最前面(左边 Left)或者最后面(右边 Right)加入或减人。

生活化场景:排队系统或者社交媒体的最新动态(Timeline)。比如你关注的博主发了新微博,就把新微博塞到你的列表最前面,你一刷新就能看到最新的。

命令演示:

java 复制代码
# 场景:记录公众号发布的最新文章 ID
# 左侧推入(LPUSH),相当于最新的文章排在最前面
LPUSH my_timeline "article_003"
LPUSH my_timeline "article_004"
LPUSH my_timeline "article_005"

# 查看最近发布的 2 篇文章(0 是第一个,1 是第二个)
LRANGE my_timeline 0 1
# 返回:"article_005", "article_004"

# 弹出最老的一篇文章(从右侧拿走并删除 RPOP)
RPOP my_timeline
# 返回:"article_003"
2.2.4 Set(集合):朋友圈的"圈子"

Set 是一个无序且不重复的元素集合。你往里面塞十个一样的东西,它也只会保留一个。而且它天生擅长做"交集、并集、差集"的数学运算。

生活化场景:抽奖系统(保证一个人只能中一次奖)、文章标签,或者最经典的"共同好友"(把你好友的 Set 和我的好友 Set 取交集)。

命令演示:

java 复制代码
# 给文章打标签,重复添加 "tech" 也只会存一个
SADD article:100:tags "tech" "coding" "redis" "tech"

# 查看这篇文章的所有标签
SMEMBERS article:100:tags
# 返回:"coding", "tech", "redis"(注意:每次取出的顺序可能不同)

# 场景:共同好友
SADD user:A:friends "Tom" "Jerry" "Spike"
SADD user:B:friends "Tom" "Spike" "Tyke"

# 找出 A 和 B 的共同好友(交集 SINTER)
SINTER user:A:friends user:B:friends
# 返回:"Tom", "Spike"
2.2.5 ZSet(Sorted Set / 有序集合):金牌排行榜

ZSet 就像是 Set 的升级版,它不仅要求元素不能重复,还会给每个元素绑定一个分数(Score),并根据这个分数自动进行排序。

生活化场景:游戏积分排行榜、微博热搜榜、直播间打赏贡献榜。有了 ZSet,老板再让你做排行榜,简直就是手到擒来。

命令演示:

java 复制代码
# 场景:游戏玩家分数排行榜,ZADD 后面跟的是 "分数 玩家"
ZADD game:leaderboard 1500 "PlayerA"
ZADD game:leaderboard 2100 "PlayerB"
ZADD game:leaderboard 1800 "PlayerC"

# 玩家 A 打赢了一局,加了 400 分
ZINCRBY game:leaderboard 400 "PlayerA"
# PlayerA 现在的分数变成 1900

# 查看排行榜前两名!(ZREVRANGE 是从大到小排,0 1 代表第一名和第二名)
ZREVRANGE game:leaderboard 0 1 WITHSCORES
# 返回:
# 1) "PlayerB"
# 2) "2100"
# 3) "PlayerA"
# 4) "1900"

2.3 通用命令

学会管理键值,比如 EXPIRE(设置过期时间)、DEL(删除)、KEYS(查找)等。

2.4 第一阶段小结

这就是 Redis 最基础也是最强大的"五大神器":

|----------|------------|
| 数据类型 | 核心用途 |
| String | 简单存取 / 计数 |
| Hash | 存对象 / 资料档案 |
| List | 队列 / 最新列表 |
| Set | 去重 / 共同好友 |
| ZSet | 排行榜优先选择 |

第三阶段:登堂入室(核心进阶功能)

掌握了基础用法后,需要了解 Redis 是如何保证数据不丢失以及如何处理复杂任务的。

3.1 持久化机制(重点)

Redis 是内存数据库,断电就没?不是的。它有 RDB(快照)和 AOF(追加文件)两种方式把数据保存到硬盘上。

3.1.1 RDB(Redis Database):给内存拍一张"全景快照"

你可以把 RDB 想象成照相机。每隔一段时间,Redis 就会给当前内存里所有的数据拍一张"快照",然后把这张照片保存成一个二进制文件(通常叫 dump.rdb)放在硬盘上。

它是怎么工作的? Redis 可以根据你的配置自动触发(比如"如果 5 分钟内有 100 个 Key 被修改了,就拍一次快照")。拍照时,Redis 主进程会克隆(Fork)出一个子进程,由子进程默默地把数据写到硬盘上,主进程继续飞速处理用户的请求,两不耽误。

优点:

  • 恢复速度极快!因为它是紧凑的二进制文件,相当于直接把完整状态搬回内存,非常适合用来做定期备份和灾难恢复。

缺点:

  • 容易丢一段数据。假设你设置了每 5 分钟拍一次快照,如果 Redis 在第 4 分钟的时候崩溃了,那这 4 分钟内新写入的数据就彻底丢失了。
3.1.2 AOF(Append Only File):事无巨细的"流水账本"

如果你数据的安全性要求极高,不能容忍丢失这几分钟的数据,那就要靠 AOF 了。你可以把 AOF 想象成一个记账本。

它是怎么工作的? 只要开启了 AOF,Redis 每执行一条会修改数据的命令(比如 SETINCR),就会把这条命令的文本直接追加记录到 AOF 文件(appendonly.aof)的末尾。当 Redis 重启时,它只需要把这个账本从头到尾重新执行一遍,就能完全恢复数据。

优点:

  • 数据极其安全。通常配置为"每秒同步一次",哪怕断电,最多也就丢失 1 秒钟的数据。

缺点:

  • 文件体积膨胀得很快(毕竟连你把一个值加 1 再减 1 都会记录两条命令记录)。而且因为文件大、记录的全是命令,重启时一条条重新执行的恢复速度,远比不上直接加载 RDB 快照。
3.1.3 RDB 与 AOF 核心对比

为了让你看得更清晰,我们用一张表格来做个总结:

|--------|------------------|-----------------|
| 特性 | RDB(快照模式) | AOF(日志模式) |
| 工作原理 | 保存某个时间点的完整数据状态 | 记录每一条修改数据的命令 |
| 文件体积 | 小(紧凑的二进制) | 大(纯文本的命令日志) |
| 恢复速度 | 快(直接加载到内存) | 慢(需要一条条重新执行) |
| 数据安全性 | 较低(会丢失两次快照之间的数据) | 极高(最多丢失 1 秒的数据) |
| 系统资源消耗 | 拍照瞬间 CPU/内存开销大 | 持续的小规模磁盘 I/O 开销 |

3.1.4 终极杀手锏:RDB + AOF 混合持久化

聪明的你可能会问:"既然 RDB 恢复快,AOF 数据全,我能不能两个都要?"

答案是:必须能! 而且这也是目前的生产环境标配。

从 Redis 4.0 开始,官方推出了混合持久化。简单来说,它会在 AOF 文件重写的时候,把当前内存的完整状态先用 RDB 的格式写在文件开头,然后再把这之后产生的新增命令用 AOF 的格式追加在后面。这样一来,重启 Redis 时,先飞速加载前半段的 RDB 快照,再把后半段的 AOF 零星命令补齐。完美实现了"恢复快"与"不丢数据"的统一!

3.2 内存管理与淘汰策略

内存满了怎么办?了解 Redis 的键过期机制以及 8 种内存淘汰策略(如 LRU、LFU)。

3.2.1 过期(Expiration)与淘汰(Eviction)的区别

在聊淘汰策略之前,需要先理清一个很多人在面试和实际开发中容易混淆的概念:

过期(Expiration):这是你主动设置的。比如你规定一个验证码 5 分钟后失效(TTL)。时间一到,Redis 就会通过"惰性删除"(等你来查的时候发现过期了再删)或"定期删除"(Redis 后台时不时扫一圈,删掉一部分过期的)来清理它们。

淘汰(Eviction):这是被动触发的。当 Redis 的内存使用量达到了你配置的上限(maxmemory),哪怕所有数据都没过期,为了能装下新的数据,Redis 也必须狠心踢掉一些老数据。

3.2.2 核心算法:LRU vs LFU

要理解淘汰策略,最关键的是搞懂 Redis 用来评判"谁该被踢"的两种核心算法。

LRU(Least Recently Used - 最近最少使用):

  • 判断标准:看的是"时间"。谁最久没有被访问过,就踢谁。

  • 生活化比喻:就像整理衣柜,那件你整整三年都没穿过的衣服,最先被扔掉。哪怕你三年前天天穿它,只要最近没穿,它就得走人。

LFU(Least Frequently Used - 最不经常使用)(Redis 4.0 引入):

  • 判断标准:看的是"频率"。在一段时间内,谁被访问的次数最少,就踢谁。

  • 生活化比喻:还是整理衣柜。有一件衣服你昨天刚穿过一次(最近用过),但过去一年你总共也就穿了这一次;而另一件衣服你过去一年穿了 100 次。LFU 会选择扔掉那件只穿过一次的衣服,留下真正的高频"爆款"。

3.2.3 Redis 的 8 种内存淘汰策略

Redis 极其灵活,它把"从哪里挑数据(范围)"和"用什么算法挑(规则)"组合起来,一共提供了 8 种策略供你选择:

  1. 佛系策略(默认设置)
  • noeviction(不淘汰):内存满了?抱歉,我不踢任何人。如果有新的写入请求,我直接报错返回。

  • 适用场景:当你把 Redis 当作绝对不能丢数据的纯数据库来用时。

  1. 从"所有数据"中挑选(allkeys- 系列)

这是最常用的场景,当你把 Redis 当作纯缓存时(通常不设置过期时间,全靠容量淘汰)。

  • allkeys-lru:把所有数据中最久没用过的踢掉。(最经典、最常用的缓存策略)

  • allkeys-lfu:把所有数据中访问频率最低的踢掉。(适合需要精准保留"热点数据"的场景)

  • allkeys-random:闭着眼睛在所有数据里随机踢一个。(极少使用,除非你的数据访问概率完全一样)

  1. 只从"设置了过期时间的数据"中挑选(volatile- 系列)

如果你既把 Redis 当缓存,又把它当数据库存了一些绝对不能丢的永久数据。那么你可以限制 Redis 只能去踢那些本来就带有寿命(TTL)的数据。

  • volatile-lru:在设置了过期时间的数据中,踢掉最久没用过的。

  • volatile-lfu:在设置了过期时间的数据中,踢掉访问频率最低的。

  • volatile-random:在设置了过期时间的数据中,随机踢。

  • volatile-ttl:在设置了过期时间的数据中,谁最快要过期了,就提前把它踢掉。

3.2.4 实战:我该怎么选?

不要被这 8 个名词吓到,在实际生产中,选择逻辑其实很简单:

如果你把 Redis 当作纯缓存,数据丢了可以去 MySQL 里重新查:

  • 首选 allkeys-lru。绝大多数公司的默认选择,逻辑简单,效率高。

  • 如果你的业务有非常明显的"头部热点"(比如微博热搜,只有极少数词条被疯狂访问),改用 allkeys-lfu 效果会更好。

如果你的 Redis 里既有缓存,又有重要的业务数据(比如用户 Session、分布式锁,没设过期时间):

  • 只能选 volatile-lruvolatile-lfu。这样 Redis 就只会在那些"早晚要死"的缓存数据里动刀子,绝对不会误删你的核心业务数据。

3.3 事务与 Pipeline

Redis 如何处理批量命令?虽然不支持像关系型数据库那样强一致性的回滚,但有自己的一套事务和流水线(Pipeline)机制来提升批量执行效率。

3.3.1 Pipeline(流水线):极致的"快递打包"艺术

痛点:Redis 处理命令的速度极快(微秒级),但网络传输是非常慢的。如果你要执行 1000 次 SET 命令,普通的做法是:发 1 条命令 → 等待 Redis 响应 → 再发第 2 条。这中间来回的网络延迟(RTT, Round Trip Time)积累起来,极其浪费时间。这就好比你搬 1000 块砖,每次只拿一块跑一趟。

这是什么? Pipeline 就像是一辆小推车。它允许客户端把这 1000 条命令打包,一次性发给 Redis 服务器;Redis 执行完后,把 1000 个结果也打包,一次性返回给客户端。

核心特点:

  • 极度提升性能:省去了大量无谓的网络等待时间,批量操作的效率会有几十倍甚至上百倍的提升。

  • 纯客户端技术:Pipeline 其实主要是客户端(比如 Java 的 Jedis/Lettuce,Python 的 redis-py)提供的一种优化手段,Redis 服务端只是配合接收而已。

  • 注意(没有原子性):Pipeline 不管顺序,也不管中途有没有被别人插队。如果在这 1000 条命令执行期间,另一个用户也发来了一条命令,Redis 可能会在中间去执行那个用户的命令。

3.3.2 Redis 事务(MULTI / EXEC):排队打饭的"一锤子买卖"

如果你不仅需要批量执行,还需要这些命令连贯执行,中间绝对不能被别人插队,那就要用 Redis 事务了。

它主要依靠几个核心命令:

  1. MULTI(开始事务):告诉 Redis,"我要开始点单了,接下来的命令先别执行,帮我记在小本本(队列)上"。

  2. 入队操作:你发送的一系列命令(如 SETINCR),Redis 会统一回复 QUEUED(已入队)。

  3. EXEC(执行事务):告诉 Redis,"我点完了,按顺序给我一次性上菜!"。Redis 会锁定这个队列,一口气把它们全部执行完,期间任何其他客户端的命令都不能插队。

  4. DISCARD(放弃事务):如果点单点到一半后悔了,发送 DISCARD,Redis 会清空刚才排队的命令,当作无事发生。

3.3.3 为什么说 Redis 事务"不支持强一致性的回滚"?

这是面试最高频的考点,也是颠覆很多人传统数据库认知的点。

在 MySQL 里,一个事务执行到一半报错了,前面成功的数据会自动回滚(Rollback),恢复到执行前的状态。但 Redis 是不回滚的!

Redis 的事务处理错误分为两种情况:

语法错误(排队时就发现):连坐,全部作废

如果你在打字时敲错了命令(比如把 SET 打成了 SSET),Redis 在入队(QUEUED)阶段就会报错。这时候如果你强行执行 EXEC,Redis 会直接拒绝,整个事务队列里所有的命令都不会执行。

运行错误(执行时才发现):尽力而为,谁错谁不管,对的继续执行

如果你语法没错,但是逻辑错了。比如你让一个正常的文字字符串去自增(对 "abc" 执行 INCR),在入队时 Redis 发现不了。等到 EXEC 真正执行时,到了这条命令会报错,但是!Redis 会忽略这个错误,继续执行队列里后面的其他命令。 前面已经执行成功的命令,也绝对不会回滚撤销。

为什么 Redis 这么"无情"? 官方给出的解释非常霸气且现实:

  1. 保持极速:回滚机制需要记录大量的历史状态,这极其消耗系统性能和内存,这与 Redis "简单快速"的底层设计哲学背道而驰。

  2. 错误只产生在开发阶段:运行时的逻辑错误(比如拿字符串去加减),通常是程序员写代码时的 Bug,这种 Bug 不应该带到生产环境中去用复杂的"回滚"来擦屁股。

3.3.4 终极护盾:WATCH(乐观锁)

有时候我们需要在事务执行前,确保某个数据没有被别人动过(比如秒杀扣库存,必须先确认库存还够不够)。这时候就需要用到 WATCH 命令。

用法:在 MULTI 之前,先执行 WATCH key(盯住这个 Key)。

效果:如果在执行 EXEC 之前,有其他客户端修改了这个被 WATCH 的 Key,那么这个事务在执行 EXEC 时就会直接失败(返回 null),相当于告诉你:"数据被别人抢先改了,你的操作作废了,请重试"。

这就叫乐观锁(CAS - Check And Set),非常轻量且高效。

3.3.5 总结对比:该用哪个?

|----------|-------------------|--------------------------------|
| 特性 | Pipeline(流水线) | Transaction(事务 MULTI/EXEC) |
| 核心目的 | 减少网络延迟,提高吞吐量 | 保证一组命令串行执行,不被插队 |
| 原子性(隔离性) | 无(会被其他客户端命令打断) | 有(执行期间绝对隔离,不被插队) |
| 错误处理 | 报错的失败,其他的继续 | 语法错全盘作废;运行错跳过,其余继续 |
| 是否回滚 | 否 | 否 |

第四阶段:融会贯通(高并发与高可用架构)

单机 Redis 扛不住了怎么办?这个阶段是系统架构师的必修课。

4.1 主从复制(Replication)

痛点:单台机器的读取能力到了极限(比如一秒钟几十万次读请求),如果让一台机器同时管读和写,它会累死。

这是什么? 我们引入"读写分离"的概念。设置一台核心机器作为主节点(Master / 老板),专门负责处理写请求(增删改)。然后给它配几个从节点(Slave / 员工),专门负责处理读请求。

怎么工作的? 老板(Master)每次把数据写到自己的账本上后,都会立刻复印一份(同步数据)发给所有的员工(Slave)。用户来查询数据时,直接找员工就行了。

优点:完美解决了"读请求"过多的问题,分摊了压力。

致命缺点:如果老板(Master)突然生病住院(宕机)了怎么办?员工们面面相觑,公司无法再接收任何写入请求,整个系统处于半瘫痪状态。直到程序员半夜被叫醒,手动去把某个员工提拔为新老板。

4.2 哨兵模式(Sentinel)

痛点:主从模式下,老板挂了需要人工干预,这在半夜发生绝对是灾难。我们需要系统能自动选出新老板。

这是什么? 为了解决单点故障,Redis 引入了"哨兵"(Sentinel)。你可以把哨兵想象成公司的"保安队"或者"董事会"。它们不负责存数据,只负责 24 小时盯着老板和员工。

怎么工作的?

  1. 监控:多个哨兵每秒钟都会给老板发送心跳包(问老板:"你还活着吗?")。

  2. 确认阵亡:如果一个哨兵发现老板没理它,它会怀疑老板挂了(主观下线)。接着它会去问其他哨兵,如果大多数哨兵都说"确实联系不上老板了",那就正式宣布老板阵亡(客观下线)。

  3. 自动选举(重点):董事会(哨兵们)立刻开会投票,从现有的优秀员工(Slave)中,根据谁的数据最新、网络最好,自动提拔他为新的老板(New Master)。

  4. 通知:哨兵把新老板上任的消息告诉所有人,并将原来的老板降级。等老老板病好(重启)回来,也只能乖乖当新老板的员工。

优点:实现了真正的高可用(HA)。就算拔掉主节点的网线,系统也能在几秒到十几秒内自动恢复,完全不需要人工干预。

致命缺点:不管你怎么选老板,始终只有一个老板在负责写数据,并且所有数据都必须装在这个老板的内存里。如果你的公司数据膨胀到了 1000GB,单台机器的内存根本塞不下怎么办?

4.3 分片集群(Cluster)

痛点:单台机器的内存容量有限(一般建议 Redis 单实例内存不超过 10-20GB),且单台机器的"写入并发"也到了极限。我们需要"横向扩容"。

这是什么? Redis Cluster 是 Redis 官方提供的终极分布式解决方案。既然一个老板管不过来,我们就设立多个老板(多 Master)!这就好比从一家单体公司,变成了拥有多个地区子公司的跨国集团。

怎么工作的?(哈希槽 Hash Slot 原理)

  1. 瓜分天下:Redis 集群引入了 16384 个哈希槽(Hash Slot) 的概念。假设我们有 3 个主节点(3 个老板),系统会把这 16384 个槽位平分给他们。

    • 老板 A 负责槽位 0 - 5460

    • 老板 B 负责槽位 5461 - 10922

    • 老板 C 负责槽位 10923 - 16383

  2. 数据归属:当你想要存一个键值对(比如 SET user:1001 "张三")时,Redis 会对这个 Key(user:1001)进行算法计算(CRC16),算出一个数字,然后再对 16384 取模,得出的结果一定在 0~16383 之间。

  3. 精准定位:假设算出来的结果是 6000,系统一看,6000 属于老板 B 的管辖范围,就会把这条数据精准地存到老板 B 的机器上。

高可用保障:当然,每个老板(Master)背后依然会跟着几个员工(Slave)。如果老板 B 挂了,老板 B 的员工会自动顶上,完全不影响老板 A 和老板 C 的工作。

优点:完美解决了海量数据存储(内存不够加机器就行)和高并发写的瓶颈。这才是支撑大厂千万级并发的终极形态!

4.4 架构演进总结表

|----------|----------------|----------------------|
| 架构形态 | 核心解决的问题 | 适用场景 |
| 单机版 | 基础使用,快速读写 | 本地开发、微型项目 |
| 主从复制 | 读写分离,分摊读压力 | 读多写少,且允许人工恢复的场景 |
| 哨兵模式 | 自动故障转移(高可用) | 中型项目,数据量在一台机器内存承受范围内 |
| 分片集群 | 海量数据存储 + 超高并发写 | 大型互联网公司、双十一、秒杀、大促 |

第五阶段:深不可测(底层原理与生产实战)

这一阶段属于高阶面试必考题和解决实际生产事故的能力。

5.1 缓存三大经典问题及解决方案

这"缓存三剑客"(缓存穿透、缓存击穿、缓存雪崩)绝对是后端开发的必修课。不仅面试官几乎必问,而且在真实的双十一、秒杀等高并发场景中,如果没有防住它们,你的数据库(比如 MySQL)可能会瞬间被流量打崩,导致整个系统瘫痪。

5.1.1 缓存穿透(Cache Penetration):查无此人的"夺命连环 Call"

这是什么? 正常情况下,用户的请求先找 Redis,找不到再去查 MySQL,查到了再写回 Redis。但是,如果有人(比如黑客)故意大量请求一个根本不存在的数据(比如 ID 为 -1 的用户,或者一个早就下架的商品)。结果就是:Redis 里肯定没有 → 只能去查 MySQL → MySQL 里也没有 → 没法写回 Redis。这样一来,Redis 形同虚设,所有的压力都直接穿透到了脆弱的数据库上。

怎么防住它?(解决方案)

  1. 缓存空对象(简单粗暴):就算 MySQL 里没查到,我也在 Redis 里存一个 Key = -1Value = null,并设置一个较短的过期时间(比如 1 分钟)。下次他再查 -1,Redis 直接返回 null,保住了 MySQL。

  2. 布隆过滤器(Bloom Filter)(高端局必备):在请求到达 Redis 之前,先加一道"超级安检门"。布隆过滤器是一种极其节省内存的数据结构,它可以极快地判断"某个数据大概率存在,或者绝对不存在"。如果安检门说这个 ID 绝对不存在,直接拦截请求,连 Redis 都不用去。

5.1.2 缓存击穿(Cache Breakdown):单点爆破的"巨星陨落"

这是什么? 注意它和"穿透"的区别。击穿针对的是"热点 Key"(比如微博上突然爆出一个超级大瓜,千万人在同时刷这一个词条)。这个热点 Key 一直在 Redis 里扛着成千上万的并发。但是,就在这个 Key 过期的那一瞬间,刚好有 1 万个并发请求打过来。这时候 Redis 里没数据了,这 1 万个请求发现缓存没命中,会同时冲向 MySQL 去查数据并试图重建缓存。MySQL 瞬间被这 1 万个相同的并发请求"击穿"而宕机。

怎么防住它?(解决方案)

  1. 互斥锁(Mutex Lock / 分布式锁):发现缓存失效时,不要让 1 万个请求都去查数据库。谁先跑到,谁就拿到一把"锁"。拿到锁的 1 个请求去查 MySQL 并重建 Redis 缓存。剩下 9999 个请求就在外面等着(休眠重试),等第一个人把缓存建好了,大家直接读缓存即可。

  2. 逻辑过期(永不过期):对于这种超级热点的数据,我们在 Redis 里根本不设置真实的过期时间(TTL),而是在它的 Value 里多存一个"过期时间"字段(比如 {"data": "热搜内容", "expire_time": "2026-03-21 15:00"})。每次读取时,程序自己判断有没有过期。如果过期了,直接把老数据返回给用户(牺牲一点点数据一致性),并在后台悄悄开一个线程去 MySQL 拉取新数据更新缓存。

5.1.3 缓存雪崩(Cache Avalanche):集体大罢工的"末日灾难"

这是什么? 击穿是"一个"热点 Key 过期,而雪崩是"一大批" Key 在同一时间集体过期,或者干脆是 Redis 服务器直接宕机了。这时候,海量的请求发现 Redis 里空空如也,全部像雪崩一样压向数据库,MySQL 连悲鸣都来不及就直接挂了。

怎么防住它?(解决方案)

  1. TTL 加随机值(防集体过期):在给一大批缓存(比如首页推荐商品)设置过期时间时,不要全部设置为绝对的 1 小时。而是 1 小时 + 随机的 1~5 分钟。把失效时间打散,避免它们在同一秒集体大罢工。

  2. Redis 高可用集群(防宕机):如果是 Redis 挂了导致的雪崩,那就必须搭建主从复制、哨兵模式或 Cluster 集群,保证哪怕坏了一台机器,Redis 也能继续提供服务。

  3. 服务降级与限流(最后的底线):如果雪崩真的发生了,在业务代码(比如微服务网关)里做限流。比如一秒钟只放 2000 个请求进来,多余的直接返回"系统繁忙,请稍后再试",宁愿牺牲部分用户体验,也要保住核心数据库不死。

5.1.4 核心总结一张表

|----------|---------------|-----------------|---------------------|
| 经典事故 | 核心原因 | 针对目标 | 主流解决方案 |
| 缓存穿透 | 请求根本不存在的数据 | 恶意攻击 / 爬虫狂刷 | 缓存空值、布隆过滤器 |
| 缓存击穿 | 单个热点数据突然过期 | 爆款商品 / 突发热搜 | 互斥锁、逻辑过期 |
| 缓存雪崩 | 大量数据同时过期 / 宕机 | 首页缓存批量失效 / 节点故障 | 过期时间加随机值、高可用架构、限流降级 |

5.2 Lua 脚本:真正的"绝对防御"

5.2.1 为什么原生事务搞不定"秒杀"?(痛点回顾)

想象一个极其经典的秒杀场景:仓库里只有 1 部 iPhone(库存 = 1),但有 1000 个人同时点下了购买按钮。

如果不用 Lua,你可能会这么写代码逻辑:

  1. 查库存:GET iphone_stock(发现库存是 1)

  2. 判断逻辑:如果库存 > 0,允许购买。

  3. 扣库存:DECR iphone_stock(变成 0)

灾难发生了(超卖):因为这三步是分开执行的。在这 1000 个人并发请求时,极大概率会有 10 个人同时执行了第一步,他们看到的库存都是 1。然后程序判断都允许购买,最后 10 个人都执行了 DECR,库存变成了 -9。老板要赔惨了!

前面提到的 WATCH(乐观锁)虽然能防止别人插队,但在秒杀这种 1000 人抢 1 个商品的极端并发下,999 个人都会因为数据被别人修改而频繁报错重试,这会导致服务器压力巨大,甚至雪崩。

5.2.2 Lua 脚本是什么?

Lua 是一种极其轻量级的脚本语言。Redis 内置了 Lua 解析器,允许客户端把一段包含复杂逻辑的 Lua 代码直接发送给 Redis 服务端执行。

为什么它能实现真正的原子性? Redis 处理命令的核心逻辑是单线程的。当 Redis 开始执行一段 Lua 脚本时,它会把这整个脚本视为"一个巨大且不可分割的超级命令"。在脚本执行完毕之前,任何其他客户端发送的命令都必须在门外排队等着。绝对不可能出现"查完库存还没来得及扣,别人就插队进来了"的情况。

5.2.3 实战:一段完美的秒杀扣库存代码

使用 Lua 脚本,我们可以把"查库存 → 判断 → 扣库存"这三步,打包成一个绝对原子的操作。

这是一段经典的扣库存 Lua 脚本:

java 复制代码
-- KEYS[1] 代表商品的库存 Key(比如 "iphone_stock")
-- ARGV[1] 代表这次想要购买的数量(比如 1)

-- 1. 先查出当前库存
local current_stock = tonumber(redis.call('GET', KEYS[1]))

-- 2. 如果库存查不到,或者库存已经为 0,直接返回 0(代表失败)
if current_stock == nil or current_stock == 0 then
    return 0
end

-- 3. 判断库存够不够扣
if current_stock >= tonumber(ARGV[1]) then
    -- 4. 如果够扣,执行扣减动作
    redis.call('DECRBY', KEYS[1], ARGV[1])
    return 1  -- 返回 1 代表扣减成功
else
    -- 5. 如果不够扣,返回 0 代表失败
    return 0
end

怎么使用它? 你只需要在 Java、Python 或 Go 的代码中,将这段文本传给 Redis 的 EVAL 命令去执行即可。Redis 会在一瞬间把这段逻辑跑完,要么成功返回 1,要么失败返回 0,干脆利落,绝不超卖!

5.2.4 现实世界的忠告:Lua 是把双刃剑

虽然 Lua 脚本极其强大,但在真实的生产环境中,作为一名资深开发者,必须给你提个醒:

绝对不要在 Lua 脚本里写耗时的逻辑! 刚才说了,Lua 脚本执行时,会阻塞其他所有的 Redis 命令。如果你在脚本里写了一个复杂的循环,或者脚本执行时间超过了哪怕几毫秒,整个 Redis 就会处于"假死"状态。所有依赖 Redis 的其他业务都会被卡住,这在生产环境中是致命的事故。

最佳实践:脚本要极其精简,只处理必须保证原子性的极短逻辑(比如上面的加减判断),千万别把它当成重型计算引擎来用。

5.3 分布式锁:从单机思维跨越到分布式架构

5.3.1 什么是分布式锁?(一个抢厕所的比喻)

你可以把分布式系统想象成一个有几十个部门(微服务实例)的大公司,但公司只有一把公共厕所的钥匙。

  • 抢锁:谁先拿到这把钥匙(在 Redis 里写入一个特定的 Key),谁就能进去办事(执行业务逻辑)。

  • 互斥:在他把钥匙还回来(删除 Key)之前,其他人就算把门敲烂,也只能在外面排队等着。

5.3.2 Redis 原生分布式锁的"进化史"

最初,大家是手写 Redis 命令来实现分布式锁的,但这里面踩过无数的坑。

初代版本:SETNX(Set if Not eXists)

这是 Redis 实现锁的最核心命令。意思是:如果这个 Key 不存在,我才能设置成功(返回 1,代表加锁成功);如果已经存在,我就设置失败(返回 0,代表别人锁了)。

java 复制代码
# 机器 A 尝试加锁
SETNX lock:iphone 1  # 返回 1,拿到锁了!

# 机器 B 尝试加锁
SETNX lock:iphone 1  # 返回 0,有人在用,拿锁失败!

致命缺陷(死锁):如果机器 A 刚拿到锁,突然宕机(死机)了,没来得及执行删除锁的命令(DEL)。这把锁就永远留在了 Redis 里,其他机器再也拿不到锁,整个业务彻底卡死。

进化版本:加上过期时间(TTL)

为了防止死锁,我们必须给锁加一个"自动销毁"的时间。即使机器 A 宕机了,时间一到,Redis 也会自动把锁删掉。

java 复制代码
# 把加锁和设置过期时间合并成一条原子命令(极其重要!)
SET lock:iphone "机器A的专属ID" NX PX 10000
# NX:不存在才设置
# PX 10000:10秒后自动过期

新的缺陷(锁被误删):假设机器 A 的业务逻辑很复杂,执行了 15 秒。但在第 10 秒的时候,锁已经自动过期了!此时,机器 B 趁机拿到了锁开始执行逻辑。到了第 15 秒,机器 A 执行完了,它去 Redis 里执行 DEL 命令,结果一不小心把机器 B 刚加的锁给删了!整个系统又乱套了。

5.3.3 Redisson 与它的"看门狗"(Watchdog)魔法

为了解决"业务没执行完,锁却提前过期了"这个世界级难题,大厂们通常不会自己手写原生 Redis 锁,而是直接引入企业级开源框架------Redisson。

Redisson 最牛的核心机制,就是一个叫做"看门狗(Watchdog)"的后台线程。

看门狗是怎么工作的?

  1. 自动续期:当你用 Redisson 加锁成功后,它不仅会设置一个默认的过期时间(比如 30 秒),还会默默在后台启动一只"看门狗"线程。

  2. 定时巡逻:这只看门狗每隔一段时间(通常是过期时间的三分之一,即 10 秒),就会去检查一下:"主人的业务代码还在运行吗?"

  3. 无限续杯:如果业务还在运行,看门狗就会自动向 Redis 发送一条命令,把锁的过期时间重新延长回 30 秒。只要你的业务没执行完,看门狗就会一直帮你"续杯",绝对不会出现锁提前失效的问题。

  4. 安全释放:当业务正常执行完毕,程序主动释放锁,看门狗也就光荣下班了。

  5. 防宕机死锁:万一拿到锁的机器突然宕机了,看门狗线程也会随之死亡,不再续期。30 秒后,锁自然过期,其他机器就能正常抢锁,完美避免了死锁!

除此之外,Redisson 的释放锁逻辑,底层用的正是我们上一节学过的 Lua 脚本。它通过 Lua 脚本原子性地判断:"这把锁到底是不是我加的?如果是,我才删除。"这就彻底解决了"误删别人锁"的问题。

5.3.4 小结:分布式锁的三大铁律

经过上面的推演,一个完美的分布式锁必须具备三个条件:

  1. 互斥性:任何时刻只能有一个客户端持有锁(依靠 SET NX)。

  2. 防死锁:客户端宕机也能自动释放(依靠过期时间 TTL)。

  3. 安全性:加锁和解锁必须是同一个人,且不能提前失效(依靠 Lua 脚本 + Redisson 看门狗)。

六、大厂面试实战模拟

6.1 第一面:缓存架构场景题(防不住就背锅)

场景:今晚双十一零点,我们有一个全网预热很久的超级爆款商品(热点 Key)。不巧的是,这个 Key 的过期时间刚好在 00:00:01 到期了。就在这一瞬间,10 万个用户的查询并发直接打过来,发现 Redis 里没数据。

问题:

  1. 这种现象在行业内叫什么?

  2. 如果这 10 万个请求同时冲向 MySQL,数据库肯定秒挂。你会用什么具体的技术手段和代码逻辑来拦截这 10 万个请求,只让 1 个请求去查数据库?

标准答案:

  1. 现象名称:这叫缓存击穿(Cache Breakdown)。特指"单个热点 Key"在过期瞬间,遭遇海量并发请求,导致请求穿透到数据库。

  2. 解决方案(互斥锁 / 分布式锁):遇到这种情况,绝对不能让 10 万个请求一起去查数据库。我会用互斥锁来控制并发,具体代码逻辑如下:

    • 第一步(查缓存):10 万个请求同时查 Redis,发现没数据。

    • 第二步(抢锁):10 万个请求同时尝试在 Redis 里加一把锁(比如用 SETNX 或者 Redisson 的 tryLock)。

    • 第三步(只有 1 个幸运儿):Redis 单线程的特性保证了这 10 万个请求中,只有 1 个请求能抢到锁。

    • 第四步(拿锁者建缓存):抢到锁的这 1 个请求,去查 MySQL 数据库,查到数据后写回 Redis 缓存,最后释放这把锁。

    • 第五步(剩下 99999 人等待):没抢到锁的请求,让它们休眠一小会儿(比如 50 毫秒),然后重新执行第一步。此时它们再去查缓存,就会发现刚刚那 1 个人已经把数据放进 Redis 了,直接读取缓存即可。完美保住了 MySQL!

6.2 第二面:底层机制原理题(懂机制才能救火)

场景:昨天凌晨,咱们机房的某台核心 Redis 服务器突然断电宕机了。你作为负责人,虽然开启了 AOF 保证了数据几乎没丢,但因为 AOF 文件已经膨胀到了 50GB,Redis 重启时一条条回放命令,花了整整 20 分钟才恢复服务,老板非常生气!

问题:我不允许降低数据的安全性(不能单纯切回容易丢数据的 RDB),但我要求你必须让这台 Redis 在几十秒内极速重启并恢复所有数据。你会怎么向我抛出你的优化方案?

标准答案:

核心方案:开启 Redis 4.0 引入的杀手锏------RDB + AOF 混合持久化。

原理解析:单纯的 AOF 文件全是文本命令,重放确实慢;单纯的 RDB 是快照,虽然快但容易丢数据。混合持久化将两者完美结合:

  • 当开启混合持久化后,Redis 在进行 AOF 重写(压缩文件体积)时,会把当前内存里的全量数据,以 RDB 快照(紧凑的二进制格式)的形式写在 AOF 文件的开头。

  • 在 RDB 快照写入期间,新产生的零星修改命令,依然以 AOF(文本格式)的形式追加在文件末尾。

最终效果:当 Redis 宕机重启时,它会先飞速加载文件前半部分的 RDB 二进制数据,瞬间恢复 99% 的数据;然后再执行后半部分那一丁点 AOF 命令,补齐剩下的 1% 数据。既保证了像 AOF 一样不丢数据,又实现了像 RDB 一样的极速重启。

6.3 第三面:分布式锁高阶实战题(写错就发错钱)

场景:你的业务系统部署了 50 台机器,你用 Redis 的 SET key value EX 10 NX 写了一个分布式锁,给锁加了 10 秒的超时时间,防止机器宕机导致死锁。但是现在线上出了个大 Bug:某台机器抢到锁后,因为网络严重卡顿,业务代码执行了 15 秒。也就是说,在第 10 秒的时候,锁已经自动失效了,第二台机器趁虚而入抢到了锁。更要命的是,第一台机器在第 15 秒执行完业务去释放锁时,把第二台机器的锁给误删了!

问题:别跟我说"把过期时间设置成 30 秒"这种治标不治本的话。我要你从底层逻辑上彻底解决"锁提前过期"和"误删别人锁"这两个致命缺陷,说出你的终极方案!

标准答案:

这道题直击分布式锁的最痛点。我的终极方案是引入类似 Redisson 框架的底层逻辑,分两步彻底解决:

  1. 解决"误删别人锁":唯一标识 + Lua 脚本
  • 加锁时:不能简单地写 SETNX lock 1,而是要把 Value 设置成当前机器和线程的唯一标识(比如 UUID + ThreadID)。

  • 解锁时:必须使用 Lua 脚本。解锁分两步:先判断 Redis 里的 Value 是不是我自己的标识,如果是,才执行 DEL 删除。因为 Lua 脚本在 Redis 中是原子执行的,所以"判断"和"删除"中间绝不会被别人插队,彻底杜绝了误删别人的锁。

java 复制代码
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
  1. 解决"锁提前过期":Watchdog(看门狗)机制
  • 我不会写死一个极长的过期时间(比如 300 秒),这不合理。

  • 我会设置一个相对较短的默认过期时间(比如 30 秒),同时在后台启动一个"看门狗"守护线程。

  • 这个看门狗会每隔 10 秒(过期时间的 1/3)去检查一下:这把锁还在不在?当前的业务逻辑执行完了吗?

  • 如果业务还没执行完,看门狗就会自动向 Redis 发起命令,把这把锁的过期时间重新"续杯"回 30 秒。只要业务不死,锁就永远不过期;一旦机器意外宕机,看门狗也跟着死了,锁在 30 秒后自然释放,绝生死锁。

七、总结与展望

7.1 完整知识图谱回顾

恭喜你!从基础数据结构、持久化、淘汰策略、缓存三大坑,再到最高阶的集群架构和分布式锁,你的 Redis 核心知识图谱已经彻底点亮了!

让我们回顾一下完整的知识架构:

第一阶段:基础入门

  • 五大基础数据类型:String、Hash、List、Set、ZSet

  • 通用命令:EXPIRE、DEL、KEYS 等

第二阶段:核心进阶

  • 持久化机制:RDB、AOF、混合持久化

  • 内存淘汰策略:8 种策略(LRU、LFU 等)

  • 事务与 Pipeline:MULTI/EXEC、WATCH、Pipeline

第三阶段:高可用架构

  • 主从复制(Replication)

  • 哨兵模式(Sentinel)

  • 分片集群(Cluster)

第四阶段:生产实战

  • 缓存三大问题:穿透、击穿、雪崩

  • Lua 脚本实现原子操作

  • 分布式锁与 Redisson

7.2 学习建议

  1. 循序渐进:不要试图一次性掌握所有内容。建议按照四个阶段逐步学习,每个阶段都要配合实践项目来巩固。

  2. 动手实践:Redis 是一个实践性很强的技术。建议在学习过程中搭建本地环境,亲自执行各种命令,观察效果。

  3. 深入源码:当你掌握了基本使用后,可以尝试阅读 Redis 的源码,深入理解其底层实现原理。

  4. 关注社区:Redis 社区非常活跃,关注官方博客和 GitHub 仓库,及时了解新特性和最佳实践。

7.3 进阶方向

掌握了 Redis 之后,你还可以继续深入学习以下相关技术:

  • MySQL:索引原理、锁、事务

  • 消息队列:Kafka、RabbitMQ

  • 分布式系统:一致性算法、分布式事务

  • 云原生:Docker、Kubernetes

八、结语

Redis 作为现代后端开发的核心组件,其重要性不言而喻。从简单的缓存工具到复杂的分布式系统基石,Redis 的发展历程体现了技术的不断演进。

通过本文的系统化学习,相信你已经建立了完整的 Redis 知识体系。记住,技术学习是一个持续的过程,保持好奇心和实践精神,你一定能在技术的道路上走得更远。

祝你学习愉快,早日成为 Redis 高手!

本文内容基于系统化 Redis 学习路线整理,涵盖了从入门到精通的完整知识体系。如有任何问题或建议,欢迎留言交流。

相关推荐
sqyno1sky2 小时前
机器学习模型部署:将模型转化为Web API
jvm·数据库·python
爱丽_2 小时前
G1 深入:Region、Remembered Set、三色标记与“可预测停顿”
java·数据库·算法
dapeng28702 小时前
机器学习与人工智能
jvm·数据库·python
洛兮银儿2 小时前
如何用python连接mysql数据库?
数据库·mysql
CDN3602 小时前
MySQL安全加固十大硬核操作及CDN的隐形守护
数据库·mysql·安全
小江的记录本2 小时前
【VO、DTO、Entity】VO、DTO、Entity三大核心数据对象全解析(附核心对比表 + 代码示例)
java·数据库·spring boot·spring·架构·mybatis·数据库架构
不想看见4042 小时前
Qt 框架中的信号与槽机制【详解】
服务器·数据库·qt
白鸽梦游指南3 小时前
redis-cluster集群实验及解析
数据库·redis·缓存
阿贵---3 小时前
构建一个基于命令行的待办事项应用
jvm·数据库·python