大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
Redis 概览:它是什么、装起来、第一次对话
这一课你将能做到
- 说清楚 Redis 是什么,以及它和 MySQL 这类磁盘数据库的分工
- 在本机用 Docker 启动 Redis 7,并用
redis-cli完成第一次读写 - 掌握键(key)的命名、过期、查看、删除这套通用操作
为什么要学
本站的编程题库里,有几类需求如果直接查 MySQL,会非常吃力:
- 用户点「提交代码」,判题服务要做限流:同一个用户 10 秒内最多提交 5 次。这种高频计数,数据库扛不住。
- 登录或找回密码要发验证码,验证码 5 分钟后必须失效。
- 课程排行榜每秒可能有上百人同时刷新。
这类需求的共同点是:读写极频繁、数据量不大、能容忍断电丢失、对过期时间有强需求。这正是 Redis 的主场。
人话:MySQL 像档案柜,东西放得久、放得规矩,但翻档案要时间;Redis 像你桌上的便签纸,伸手就拿到,下班可以清空。两者不是替代关系,是配合关系。本课程聚焦 Redis 本身,不讨论与数据库之间的数据同步。
先建立图像
Redis 全称 Remote Dictionary Server,本质是一个跑在内存里的键值(Key-Value)数据库。你可以把它想成一个巨大的、所有客户端共享的字典:
应用服务器(判题服务 / 网站后端)
│
│ 命令:SET captcha:13800000000 482916 EX 300
▼
┌───────────┐
│ Redis │ 单线程处理命令,内存操作,微秒级
│ 键值字典 │
└───────────┘
│
▼
captcha:13800000000 → "482916" (300 秒后自动消失)
关键点有三个:
- 数据主要在内存里,所以快;
- 值不只是字符串,还可以是列表、集合、哈希、有序集合等「数据结构」;
- 每个键都可以设置 TTL(Time To Live,存活时间),到期自动删除。
跟着做
步骤 1:启动 Redis 7
最省事的方式是用 Docker。确认本机装了 Docker 后执行:
docker run -d --name redis7 -p 6379:6379 redis:7
查看容器是否正常运行:
docker ps
不用 Docker 也可以:macOS 用 brew install redis,Ubuntu 用 apt install redis-server,Windows 推荐继续用 Docker。
步骤 2:进入命令行客户端
docker exec -it redis7 redis-cli
看到下面的提示符,就表示连上了:
127.0.0.1:6379>
先打个招呼,确认服务存活:
127.0.0.1:6379> PING
PONG
查看 Redis 版本,确认是 7.x:
127.0.0.1:6379> INFO server
redis_version:7.2.x
...
步骤 3:第一次读写
模拟存一个手机验证码:
127.0.0.1:6379> SET captcha:13800000000 482916
OK
127.0.0.1:6379> GET captcha:13800000000
"482916"
SET 是写入,GET 是读取,返回 nil 表示键不存在:
127.0.0.1:6379> GET captcha:13900000000
(nil)
步骤 4:让键自动过期
验证码必须 5 分钟失效,写入时直接带上 EX(单位秒):
127.0.0.1:6379> SET captcha:13800000000 482916 EX 300
OK
127.0.0.1:6379> TTL captcha:13800000000
(integer) 297
TTL 查看剩余存活秒数,返回 -2 表示键已经不存在,-1 表示键存在但没有过期时间。
给已存在的键补设过期时间用 EXPIRE,取消过期用 PERSIST:
127.0.0.1:6379> EXPIRE captcha:13800000000 60
(integer) 1
127.0.0.1:6379> PERSIST captcha:13800000000
(integer) 1
步骤 5:查看、删除、判断类型
127.0.0.1:6379> SET course:redis:progress:1001 35
OK
127.0.0.1:6379> TYPE course:redis:progress:1001
string
127.0.0.1:6379> EXISTS course:redis:progress:1001
(integer) 1
127.0.0.1:6379> DEL course:redis:progress:1001
(integer) 1
127.0.0.1:6379> EXISTS course:redis:progress:1001
(integer) 0
想看库里现在有多少键:
127.0.0.1:6379> DBSIZE
(integer) 3
步骤 6:用 SCAN 而不是 KEYS 找键
测试时你可以用 KEYS * 列出全部键,但生产环境严禁使用——数据量大时它会阻塞 Redis 好几秒,期间所有请求都卡住。正确姿势是 SCAN,游标式分批扫描:
127.0.0.1:6379> SCAN 0 MATCH captcha:* COUNT 100
1) "128"
2) 1) "captcha:13800000000"
第一行返回的是下一次的游标,游标回到 0 表示遍历完了。第二行是本次匹配到的键。
步骤 7:键命名规范
本站统一用冒号分层,见名知意:
业务:对象:标识[:子属性]
captcha:13800000000 手机验证码
ratelimit:judge:user:1001 用户 1001 的判题限流计数
rank:course:redis:weekly Redis 课程周排行榜
progress:user:1001:course:7 用户 1001 在课程 7 的进度
键名尽量短(省内存),但要可读;不要用空格、换行和中文。
讲清楚要点
- Redis 快的根本原因是内存 + 单线程事件模型:核心命令在一条线程里顺序执行,没有锁竞争和上下文切换,复杂度 O(1) 的命令通常在微秒级完成。注意「单线程」指命令执行,Redis 7 的后台持久化、异步删除仍由其他线程负责。
- 五种基础数据结构必须先记牢:String(字符串/计数)、List(列表)、Set(集合)、Hash(哈希)、Sorted Set(有序集合),另外还有 Stream、Geo、HyperLogLog、Bitmap 等扩展,后面的课会逐个讲。
- TTL 是 Redis 的一等公民:
SET ... EX、EXPIRE、PEXPIRE(毫秒)、EXPIREAT(指定时间戳)都可以管理生命周期。凡是「临时数据」都应该显式设置过期时间,避免键无限堆积。 - 数据库编号:Redis 默认有 16 个逻辑库(编号 0-15),用
SELECT 1切换。生产环境不建议靠编号隔离业务,更推荐用键前缀或独立实例。 - 命令不区分大小写,键区分大小写:
set和SET等价,但user:1和USER:1是两个键。
你可能会懵的地方
-
Redis 数据放内存,断电不就全没了? 默认确实会丢,但 Redis 有 RDB 快照和 AOF 日志两种持久化手段(第 10 课细讲)。像验证码、限流计数这类数据本来就允许丢;排行榜这类不能丢的,可以开启持久化或由其他数据源重建。
-
既然单线程,为什么还能支撑高并发? 因为瓶颈不在 CPU 而在网络和内存 IO。Redis 用 IO 多路复用(一个线程同时盯着成千上万条连接),加上纯内存操作,单实例也能达到十万级 QPS。Redis 6 以后网络读写还引入了多线程,但命令执行依然是单线程。
-
redis-cli 里返回的 (integer)、(nil)、OK 都是什么?
OK表示操作成功;(integer) N是整数结果(比如影响了几个键、计数是多少);(nil)表示不存在。不同编程语言的客户端会把它们映射成各自的类型。 -
一个键能存多大? String 单个值最大 512 MB。但实际开发中键和值都应该很小,存大对象会阻塞网络和单线程,是典型的反模式。
-
生产环境还能直接裸连吗? 绝对不行。必须设置密码(或 ACL 账号)、禁止外网暴露、关闭危险命令,这些在第 11 课讲。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
生产用 KEYS * 找键 | 全库扫描,阻塞主线程 | 用 SCAN 游标分批遍历 |
FLUSHALL 清理「测试数据」 | 清空所有逻辑库,无法恢复 | 只 DEL 指定键,或用独立测试实例 |
键名随意起 a1、tmp | 一周后没人认识,还易冲突 | 业务:对象:标识 分层命名 |
| 存缓存不设 TTL | 内存只涨不降,最终 OOM | 临时数据一律设置过期时间 |
用 SELECT 15 隔离正式业务 | 逻辑库之间仍抢同一进程资源 | 用独立实例或集群隔离 |
| 在一个值里塞几 MB JSON | 单次读写拖慢所有客户端 | 拆成小键或用 Hash 分字段 |
卡点急救
- 连不上,报
Could not connect to Redis:先docker ps看容器在不在;再看端口是否被占用(6379是默认端口);容器没起来用docker logs redis7看错误。 (error) NOAUTH Authentication required:实例设置了密码,用AUTH 密码或AUTH 用户名 密码认证后再操作。- 设了 TTL 的键马上就没了 / TTL 返回 -2:检查是不是被别的逻辑
DEL了,或重复SET时没带过期时间——SET会清掉键上原有的 TTL,需要的话用KEEPTTL选项保留。
面试常问
-
Redis 为什么快? 纯内存操作;单线程执行命令,避免锁竞争和上下文切换;IO 多路复用处理海量连接;高效的自研数据结构(跳表、压缩列表等)。
-
Redis 常见使用场景有哪些? 缓存、计数器与限流、排行榜(Sorted Set)、验证码与会话(带 TTL)、分布式锁(SET NX EX)、消息队列(List/Stream/Pub-Sub)、集合运算(共同好友/标签)。
-
TTL -1 和 -2 分别是什么意思?
-1:键存在且没有设置过期时间;-2:键不存在。
自测三问
- 不用
KEYS,如何分批找出所有以captcha:开头的键? - 想让一个键在 300 秒后自动消失,写出两种写法。
- Redis 相比 MySQL,适合承担什么样的数据?请说出三个特征。
小结一句话
Redis 是一个带 TTL、数据结构丰富、纯内存操作的键值存储,记住「内存、单线程、五种结构、键要分层命名、过期要显式设置」这五件事,你就入门了。
延伸
- Redis 官方文档
- redis-cli 命令参考
- 下一课:String 与 Bitmap——用计数器做判题限流,用位图统计做题打卡。