CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Redis 缓存入门/课时/CLI 与键命名
RawBlame
课时目录12 节

Redis 缓存入门

  1. 01Redis 是什么
  2. 02CLI 与键命名
  3. 03String 与计数
  4. 04Hash / List / Set / ZSet
  5. 05过期与淘汰
  6. 06缓存模式
  7. 07Spring Data Redis
  8. 08会话与 Sa-Token
  9. 09Docker 运行 Redis
  10. 10Pub/Sub 入门
  11. 11测试与监控
  12. 12综合练习

CLI 与键命名

redis-cli、KEYS 慎用、命名规范。

25 分钟

redis-cli 实战:学会「看」Redis

这一课你将能做到

  1. 熟练使用 redis-cli 完成键的增删改查:SET/GET/DEL/EXISTS/TYPE/RENAME/TTL,并准确解释每个返回值(OK / (nil) / (integer))的含义
  2. 用 SCAN 游标方式遍历键空间,用自己的话说清为什么生产环境禁用 KEYS *(单线程阻塞)
  3. 按「项目:模块:实体:id」规范设计 key,能用 MEMORY USAGE 查看单个 key 的内存占用,并说出本站三类 key 前缀的分工

为什么要学

上一课你已经能 SET/GET。但真实项目里你面对的不是三五个 key,而是成千上万个。本站生产 Redis 里至少有三类 key 并存:

  • satoken:login:token:xxxx——每个在线用户一条
  • rl:203.0.113.7——每个被限流统计的 IP 一条
  • coderoadmap:tracks:list——业务缓存

不会用命令行查看、筛选、统计这些 key,你就是在蒙眼操作:排查「缓存为什么没生效」,你需要 EXISTS 和 TYPE 确认 key 状态;排查「Redis 内存怎么涨了」,你需要 MEMORY USAGE 定位大 key;批量清理一类数据,你需要 SCAN——而用错 KEYS * 可能把线上 Redis 卡死几秒甚至几十秒,所有接口跟着超时。

redis-cli 是 Redis 的手术刀。本 track 后面每一课的验证步骤都依赖它,这一课把它练熟,后面才不卡壳。

先建立图像

Redis 的键空间可以想成一栋大楼的储物柜,每个柜门贴着唯一标签(key):

db0(默认库)
 ├─ satoken:login:token:8f3a...   → 柜内有值,类型 string,TTL 86400s
 ├─ rl:203.0.113.7                → string 计数器,TTL 60s
 ├─ coderoadmap:tracks:list       → string(JSON),TTL 300s
 └─ user:1001:bookmarks           → set

对单个 key 的操作都是「按柜门标签定位」:GET 开柜看货、TYPE 问材质、TTL 看电子标签的倒计时、DEL 整柜拆掉、EXISTS 只看柜子在不在。

而 KEYS 和 SCAN 是两种「巡楼」方式:

KEYS *     → 一次性把所有柜门标签抄到一张纸上再返回(巡楼期间整栋楼封锁)
SCAN 0     → 从 0 号门开始,每次只抄一小段,返回「下次从哪继续」的游标(不封锁)

人话:key 像文件路径,冒号像文件夹分隔符。乱起名等于所有文件扔在桌面上,删错就哭。

跟着做

步骤 1:确认 Redis 在跑并进入交互模式

docker start redis-dev 2>/dev/null; docker exec -it redis-dev redis-cli

(用的是第 1 课创建的容器;如果没创建过,先执行 docker run -d --name redis-dev -p 6379:6379 redis:7-alpine。Windows 本机没装 redis-cli 也没关系,docker exec 用容器内的即可。)

步骤 2:键的增删改查基础六连

依次执行,注意观察每个返回值:

SET user:1001:name "xiaolin"
GET user:1001:name
EXISTS user:1001:name
TYPE user:1001:name
RENAME user:1001:name user:1001:nickname
GET user:1001:nickname
DEL user:1001:nickname
GET user:1001:nickname

预期输出依次是 OK、"xiaolin"、(integer) 1、string、OK、"xiaolin"、(integer) 1、(nil)。

要点:EXISTS 返回 1/0;DEL 返回实际删掉的个数(删不存在的 key 返回 0、不报错);(nil) 表示 key 不存在,不是错误。

步骤 3:体验 KEYS 和 SCAN 的区别

先在容器里批量造 20 个演示 key:

docker exec redis-dev sh -c 'for i in $(seq 1 20); do redis-cli SET "book:$i" "v$i" > /dev/null; done'

回到交互模式,对比两种遍历:

KEYS book:*
SCAN 0 MATCH book:* COUNT 5

KEYS 一次返回全部;SCAN 返回「一小批 key + 一个新游标」。把输出里的游标数字填回 SCAN <游标> MATCH book:* COUNT 5 继续扫,直到游标回到 0 为止。亲手走完这个循环,SCAN 才算真的会了。

步骤 4:--raw 解决中文显示

SET greet "你好,Redis"
GET greet
exit
docker exec -it redis-dev redis-cli --raw
GET greet

默认模式下中文显示成 \xe4\xbd\xa0\xe5\xa5\xbd 这样的 UTF-8 字节转义(看起来像乱码,但数据没坏);--raw 按原始字节输出,终端就能正常显示中文。日常排查中文内容一律加 --raw。

步骤 5:MEMORY USAGE 与键空间统计

docker exec redis-dev sh -c 'redis-cli SET big:string "$(yes a | head -n 10000 | tr -d "\n")"'
docker exec -it redis-dev redis-cli
MEMORY USAGE big:string
DBSIZE

MEMORY USAGE 返回该 key 占用的字节数(含元数据开销,10000 字符的字符串大约返回 12000 左右);DBSIZE 返回当前库的 key 总数。生产排查「内存去哪了」就靠这两个命令按前缀逐类摸底。

步骤 6:对照本站的 key 命名规范

本站 Redis 里三类前缀、三种责任:

satoken:login:token:...   ← Sa-Token 框架内部命名(框架决定,别手工改)
rl:{clientKey}            ← RedisRequestRateLimiter 里的 "rl:" + key
coderoadmap:tracks:list   ← 业务缓存(综合实战课你会亲手写)

命名规范:项目:模块:实体:id,全小写,冒号分层,不用空格、不超长。好处有三个:SCAN MATCH 能按前缀批量定位;一眼看出数据归属;清理脚本永远不会误删别的模块。

讲清楚要点

  1. KEYS 是 O(N) 全量遍历,执行期间阻塞整个 Redis:命令执行是单线程,百万级 key 的 KEYS * 可能卡几秒,期间所有请求排队。生产禁用(运维甚至会在配置里 rename-command KEYS "" 直接废掉它)。
  2. SCAN 是分批游标遍历,不阻塞:每次只扫一小批(COUNT 只是提示值,返回数量可能多于或少于它),返回新游标,游标回到 0 表示遍历结束。遍历期间 key 有增删时结果「不精确但可用」,对缓存清理场景完全够。
  3. 返回值就是协议:(nil) = 不存在,(integer) 1 = 存在/成功个数,OK = 成功。看返回值调试,比猜快得多。
  4. --raw 是给人看中文和给脚本用的;默认转义模式是给协议调试用的,两者不是数据坏了没坏的区别。
  5. RENAME 是原子操作:可用于无停机换 key;注意 RENAME 到已存在的 key 会直接覆盖目标。
  6. 命名规范是防事故的第一道墙:satoken: / rl: / coderoadmap: 三类前缀分立,保证清理脚本永不误删登录态。

你可能会懵的地方

  • KEYS 在开发机跑一下也不行吗? 开发机 key 少,跑一下没事。危险的是把「开发机随手 KEYS」的习惯带进生产——肌肉记忆要用 SCAN 练出来。

  • SCAN 的 COUNT 5 是精确返回 5 个吗? 不是。它是「这一批大概扫多少个桶」的提示,实际返回数量可能多也可能少。判断遍历是否结束只看游标是否回到 0,不看数量。

  • 为什么有 db0~db15 十六个库?能不能当多租户用? 历史遗留设计。官方明确不建议:库无法按业务命名、集群模式下只有 db0。业务隔离靠 key 前缀,不靠库编号——本站只用 db0。

  • TYPE 都有哪几种返回值? string / list / set / zset / hash / stream。本站业务缓存全是 string 存 JSON,其他类型出现在框架(Sa-Token)或你主动选用高级结构时(第 4 课)。

  • EXISTS 调多了会不会慢? EXISTS k1 k2 k3 一次传多个 key 是 O(N) 但纯内存查找,微秒级。真正要警惕的是 KEYS、SMEMBERS 大集合这类「返回大数据」的命令,阻塞和流量都来自它们。

错法对照

错法问题正解
生产环境敲 KEYS *单线程阻塞,全站请求排队SCAN 0 MATCH xxx COUNT 100 游标遍历
key 命名随手起(t1、temp_list2)无法批量定位,误删难排查coderoadmap:track:{slug} 分层命名
中文显示乱码以为是数据坏了只是客户端转义显示redis-cli --raw 重连
用 GET 确认存在再 DEL两次往返且有竞态直接 DEL,看返回个数
用 db1~db15 做业务隔离官方不建议,集群不支持key 前缀隔离,固定 db0
随手 DEL satoken:*「清理」把真实用户踢下线只删自己前缀,satoken 只读

卡点急救

  1. NOAUTH Authentication required:连的实例设了密码。交互模式里先 AUTH 你的密码,或连接时用 redis-cli --askpass(交互输入,避免明文进 shell 历史)。
  2. 中文显示成 \xe4\xbd\xa0:默认协议转义模式,exit 后用 redis-cli --raw 重进。
  3. WRONGTYPE Operation against a key holding the wrong kind of value:对 string key 执行了 list 命令之类。先 TYPE key 看类型再选命令;要换类型先 DEL。
  4. SCAN 一直停不下来:终止条件是游标返回 0。每次把输出里的新游标填回 SCAN,别每次都从 0 开始。
  5. Connection refused:容器没起或端口没映射。docker ps 确认 0.0.0.0:6379->6379/tcp 在列;不在就 docker logs redis-dev 看报错。

面试常问

  • 为什么生产禁用 KEYS?SCAN 好在哪? KEYS 一次性 O(N) 遍历,Redis 命令单线程执行,期间所有请求被阻塞;SCAN 分批 + 游标,每批开销小、不阻塞。代价是遍历期间结果不保证精确(可能重复或漏),缓存清理这类场景可以接受。

  • 你们项目的 Redis key 是怎么设计的? 三类前缀:satoken:(Sa-Token 框架会话)、rl:(限流计数,RedisRequestRateLimiter 拼接)、coderoadmap:(业务缓存,如 coderoadmap:tracks:list)。统一规范是 项目:模块:实体:id、全小写冒号分层,便于 SCAN MATCH 批量定位、防止跨模块误删。

  • 怎么定位 Redis 的大 key? 单个 key 用 MEMORY USAGE;全库排查用 redis-cli --bigkeys(内部就是 SCAN,不阻塞),或者离线分析 RDB 文件的 rdb-tools。

自测三问

  1. DEL 一个不存在的 key 返回什么?EXISTS 呢?TTL 对「存在但永不过期」的 key 返回什么?
  2. SCAN 的终止条件是什么?COUNT 参数是精确值还是提示值?
  3. 本站三类 key 前缀分别是什么?各自存什么数据?为什么必须分立?

小结一句话

redis-cli 的核心是「按 key 精确操作 + SCAN 游标遍历」:生产永远用 SCAN 代替 KEYS,用分层前缀把键空间管理成可维护的目录树。

延伸

  • redis-cli 官方文档
  • SCAN 命令
  • 下一课:String 与计数器——SET 的 NX/EX 选项、INCR 原子计数,以及本站限流器 RedisRequestRateLimiter 的逐行源码解读。
加载本节练习…
← 上一课Redis 是什么下一课 →String 与计数