开了很多次技术分享会,发现一个几乎是规律的现象:只要是聊后端基础组件,Redis 一定是被提起最多的那个。它看起来上手极其简单,无非就是 GET、SET,但真正用起来,很多人卡在了“看着全会,一写就废”的状态。这篇文章就是为“初步学习 Redis”的人写的,我把一个纯新手从零到一的路程完整捋一遍:从环境安装、数据类型、可视化工具,再到分布式锁、缓存治理和线上报错排查,全部用我真实踩过的坑来讲。适合刚入行后端、准备转岗开发,或者已经用了 Redis 但只会简单存取的人。按这个顺序读,大概一周时间,你就能从“听过 Redis”进步到“敢在生产环境里用它”。
1. 先搞清楚 Redis 到底解决什么问题
1.1 它不是替代 MySQL,而是数据库前面的“中间层”
第一个要纠正的认知,就是别把 Redis 当成替代 MySQL 的东西来学。Redis 高性能是因为数据在内存里,但你如果把核心业务数据只放在内存里,一旦进程重启、机器故障,数据就会丢得干干净净。虽然有 RDB 快照和 AOF 日志这两种持久化手段,它们能做到的,也只是把丢数据的范围缩小到秒级或者改写级别,而不是像数据库那样面向“不丢数据”来设计的。
我做过的社区项目里,用户资料、文章正文都存在 MySQL,Redis 里只放“用户登录 token、首页热点文章列表、点赞的用户 ID 集合、排行榜分数”这些高频且允许偶尔丢失的数据。数据丢了,最多就是用户重新登录、首页重新查一次库,不会造成资损。这样的设计给了 Redis 一个准确的身份:它是挡在数据库前面的中间件,不是一个最终的存储底座。“Redis 做中间件”这几个字,应该作为你理解 Redis 的主线。
那它凭什么能挡流量?因为单线程处理命令、纯内存操作,Redis 单实例的吞吐量可以做到每秒几十万次读操作,而 MySQL 在同样的机器上每秒能处理的查询是三五千量级。热点接口如果每次都查 MySQL,QPS 稍微上来就会把数据库连接池打满。把热点数据提前放进 Redis,读请求直接走内存,数据库的负载一下就降下来了。
1.2 把 Redis 看成“内存数据结构服务器”而不是“KV 存储”
很多人学 Redis 有一个弯路:拿到命令手册就开始背,今天记 SET、GET,明天记 LPUSH、LRANGE,背了一堆,但遇到真实需求还是不会用。原因在于,Redis 的价值不仅在于“能存键值对”,更在于它为每一种数据结构提供了原生的操作命令,相当于把常见业务逻辑下沉到了存储层。
举几个直观的例子。你要做文章点赞功能,要判断“用户是否已经点过赞”,用集合的 SADD 存用户 ID,用 SISMEMBER 查询,一个命令就完成去重判断,不需要把整个列表捞到程序里遍历。你要做排行榜,用有序集合 ZADD 把分数写进去,ZRANGE 直接能拿到名次区间。你要统计访问量,用字符串的 INCR 自增即可。这些操作如果在 MySQL 里做,要么写复杂的 SQL,要么多次读写再在程序里计算,效率差得多。
这也是为什么很多公司面试时喜欢考 Redis 数据类型——不是考你背了多少命令,而是看你能不能把“需求”映射到“数据结构”上。把这个观念建立起来,后面学命令才有方向。
1.3 它和本地缓存、Memcached 的区别
既然 Redis 常被当成缓存来用,就难免会跟本地缓存(比如 Caffeine、Guava Cache)和 Memcached 放在一起比较,理清区别对技术选型很有帮助:
| 维度 | Redis | Memcached | 本地缓存 |
|---|---|---|---|
| 存储位置 | 独立服务,内存 | 独立服务,内存 | 应用进程内 |
| 数据结构 | String / Hash / List / Set / ZSet 等 | 简单 KV | 由编程语言决定 |
| 持久化 | 支持 RDB / AOF | 不支持 | 不支持 |
| 分布式能力 | 主从、集群、哨兵 | 服务端分布式但结构简单 | 无,只能本机用 |
| 网络开销 | 有网络 IO | 有网络 IO | 无网络 IO,最快 |
| 典型场景 | 共享缓存、分布式锁、排行榜、队列 | 纯 KV 缓存 | 单机高频访问 |
本地缓存速度最快,因为它连网络都不走,但问题在于多个应用实例之间的数据不共享,每台机器各存各的;Memcached 能解决共享问题但数据结构太单薄,想做个排行榜都得在客户端拼。Redis 正好在“丰富的数据结构”和“多实例共享”之间找到了平衡点。我在项目里的习惯是:能接受短暂不一致的极热点数据用本地缓存挡第一层,需要多实例共享的用 Redis 做第二层,数据库只承接真正的写请求和未命中的读请求。
2. 环境搭建:从零装好 Redis
2.1 Linux 上源码安装与 apt 安装怎么选
学 Redis 第一步肯定是把它跑起来。这里给个很现实建议:不要只满足于apt install redis-server能跑就行,最好完整走一遍源码编译安装,因为你后面排查诡异问题、编译 Redis 扩展模块时,都需要了解编译过程。源码安装步骤其实很固定:
wget https://download.redis.io/releases/redis-7.2.4.tar.gz tar xzf redis-7.2.4.tar.gz cd redis-7.2.4 make -j4 make install编译完成后,redis-server 和 redis-cli 会被安装到 /usr/local/bin 下。我习惯先建一个独立的配置和数据目录:
mkdir -p /etc/redis /data/redis cp redis.conf /etc/redis/然后根据机器情况修改 redis.conf 里的几个关键项,启动时用redis-server /etc/redis/redis.conf指定配置文件。
关于版本选择,我推荐用 7.x。Redis 5.0 开始引入 Stream 数据类型,6.0 支持多线程 IO 和 ACL 访问控制,7.0 又改进了持久化与缓存淘汰策略。虽然初学者学的是核心概念,但版本太老会遇到网上资料和实际命令对不上的麻烦。选一个稳定的 7.x 版本,社区资料最多,踩坑时也更好搜。
2.2 macOS 安装:最省心的 Homebrew 方案
如果你手头是 Mac,那安装 Redis 是最简单的。直接:
brew install redis brew services start redis启动后用redis-cli ping验证,返回 PONG 就是通了。Homebrew 会把配置文件放在/opt/homebrew/etc/redis.conf(Apple Silicon)或/usr/local/etc/redis.conf(Intel),日志和持久化文件的路径也能在这个文件里看到。
需要注意一个问题:brew services start redis会让 Redis 在后台常驻,开机也会自启,这对个人开发机很方便。但如果你想练“手动启动、手动关”的运维手感,就改用:
redis-server /opt/homebrew/etc/redis.conf redis-cli shutdown不要在开发机上长期用默认端口跑多个 Redis,很容易把不同项目的环境搞混。真实项目里,多实例最常见的做法是给每个实例配置不同端口,或者用 Docker 容器隔离。
2.3 Docker 安装 Redis 和主从复制的一次性搭建
用 Docker 装 Redis 最大的好处是干净、可重复。我第一次搭主从就是用 Docker,一条命令拉起主节点:
docker run -d --name redis-master \ -p 6379:6379 \ -v /data/redis-master:/data \ redis:7.2-alpine redis-server --appendonly yes然后启动从节点:
docker run -d --name redis-slave \ -p 6380:6379 \ --link redis-master \ redis:7.2-alpine redis-server --slaveof redis-master 6379这个--slaveof参数,其实就是“跟着谁同步数据”。Docker 环境里容器之间用--link做互访时,redis-master会被解析成主容器的 IP。不用--link也可以,通过docker exec -it redis-slave redis-cli REPLICAOF redis-master 6379在运行时把主从关系建立起来。
主从复制的作用要讲明白:第一是读写分离,把读流量分一部分给从库;第二是高可用基础,主节点挂了可以切到从节点。不过 Redis 的复制默认是异步的,主节点写成功后,数据可能还要过一会儿才同步到从节点,如果这时候主节点宕机,最近一小段数据就可能丢。线上要结合WAIT命令或半同步做取舍,初学者先了解这个机制就行。
搭建完以后,用redis-cli -p 6380 info replication查看从节点的角色和主节点地址,看到role:slave就说明成功了。实验环境里可以存一个 key,再从从节点读,验证同步是否生效。
2.4 连接前必做的安全配置
绝大多数初学者第一次启动 Redis 后,直接用默认配置就跑起来了,这在本地没问题,但如果你的云服务器没有限制端口,Redis 就成了别人眼中的“肉鸡”。之前经常出现 Redis 未授权访问被入侵的案例,原因就是默认配置下 Redis 监听所有网卡、没有密码。所以下面的配置必须养成习惯:
bind 0.0.0.0 protected-mode yes requirepass your-strong-password生产环境我建议把bind改成内网 IP 或具体网段,不要用0.0.0.0;密码至少 16 位以上的随机串。修改配置后重启,再用redis-cli -a your-strong-password ping验证。-a这种命令行带密码的方式只适合测试机,线上建议用REDISCLI_AUTH环境变量或者配置文件里的密码项,避免密码出现在 shell 历史里。
3. 数据类型与核心命令:理解 Redis 的存储思维
3.1 五种基础数据类型到底该怎么记
国内面试和初级项目里,最常被问到的就是 String、Hash、List、Set、ZSet 这五种类型。与其死记命令,不如先看它们各自解决什么问题:
| 类型 | 底层形态 | 典型场景 | 关键命令 |
|---|---|---|---|
| String | 字符串/数字/二进制 | 缓存对象、计数器、token | SET、GET、INCR、SETNX |
| Hash | 字段-值映射 | 用户资料、商品信息 | HSET、HGET、HGETALL |
| List | 有序字符串列表 | 消息队列、最新列表 | LPUSH、RPOP、LRANGE |
| Set | 无序去重集合 | 点赞、标签、去重 | SADD、SISMEMBER、SUNION |
| ZSet | 带分数的有序集合 | 排行榜、延时任务 | ZADD、ZRANGE、ZRANK |
上面这份表只是用来建立第一印象。真正建立存储思维,需要动手写一遍,把自己代入到业务里。比如设计“用户中心”,你会选 Hash 存用户资料,因为HSET user:10001 name "Tom"、HSET user:10001 age 18可以多次只更新一个字段,HGETALL user:10001一次取全量;如果你用一个大 String 存 JSON,更新年龄就得把整个 JSON 读出来再写回去,成本高且容易出错。
3.2 用一条业务链路串起常用命令
命令背了容易忘,但跟着一条完整业务链路走,会清晰很多。假设你在做一个社区论坛,可以这样操作:
- 用户登录后生成 token:
SET login:token:u10001 "a1b2c3" EX 7200,表示 7200 秒过期,这是最经典的 token 缓存。 - 获取用户基本信息:
HSET user:10001 name "Tom" signature "hello",之后HGET user:10001 name直接拿字段。 - 用户给文章点赞:
SADD article:42:liked_users 10001,查询是否点过赞用SISMEMBER article:42:liked_users 10001,一个命令返回 0 或 1。 - 统计文章点赞总数:
SCARD article:42:liked_users,其实就是取集合元素个数。 - 维护“今日热榜”:
ZINCRBY hot:rank:20250420 5 article:42,把文章 ID 的分数加 5,随后ZREVRANGE hot:rank:20250420 0 9就能拿到前 10 名。
这套链路跑下来,你会发现在很多场景下,Redis 一两条命令就完成一个业务逻辑,不用写复杂的 SQL,也不用在程序里做二次聚合。
另外提醒一句:Redis 里所有命令都是原子性的,不用担心高并发下 INCR 自增会丢更新。比如INCR article:42:view_count在多进程并发执行时,Redis 会一个接一个处理,不会出现“两个进程同时读到 10,最后写回 11”的情况。
3.3 key 命名规范与过期时间设计
没有规定说 Redis 的 key 只能叫一个单词,所以最好用键名格式表达逻辑。我的习惯是“业务域:对象类型:对象ID[:字段]”,比如user:info:10001、article:content:42。这样做的直接好处是:用redis-cli --scan --pattern "user:*"能列出某类业务的所有 key,排查问题时按前缀一搜一个准。
过期时间设计也值得单独说。很多新手只会给 key 设置默认过期时间,不考虑业务访问特点。比如登录 token,过期时间应该跟登录有效期挂钩;热点文章列表,缓存 5 分钟可以,缓存 1 小时也可以,核心原则就是“允许短时间丢了重新查库”。把过期时间设置得太长,一是内存压力大,二是数据变更后旧值迟迟不失效,容易给线上造成“延迟错乱”的体验。
3.4 序列化问题:String 里到底放什么
搜索“Redis 序列化”的人特别多,因为这在 Java / Spring Data Redis 的项目里几乎必踩。你需要知道:Redis 本身只存字节,不管你往里放整数、JSON 字符串还是 Java 对象,最终都会变成字节数组。客户端怎么把对象变成字节、怎么把字节变回对象,这个转换过程就是序列化。
Java 官方自带的 JDK 序列化简单省事,但坏处很明显:序列化后体积大、只能在 Java 环境里反序列化、还有安全风险(反序列化漏洞)。所以在业务缓存里,我更推荐用 JSON 方式,比如 Jackson / Gson,把对象转成 JSON 字符串再 SET 进 Redis。这样在 redis-cli 里看到的是可读的文本,排查问题时直接 GET 就能看到字段内容,而不是一堆看不懂的二进制。
具体的坑是:如果同一个 Redis 里,不同服务用了不同的序列化方式,就会导致“写入的是 A 格式,读出来解析报错”。我见过一次生产事故,两个服务连同一个 Redis,一个用 JDK 序列化,一个用 JSON 序列化,互相读不了对方的 key。所以项目里最好统一定义序列化规范,能用 JSON 就别用 JDK。
4. 连接与可视化:自己练手时的最佳姿势
4.1 redis-cli 是基本功,别一开始就依赖图形工具
可视化工具确实方便,但我建议初学者至少在练习阶段把 redis-cli 用熟。原因很简单:你在服务器上排查问题,没有图形界面,最后靠的都是 redis-cli;图形工具就算连不上,你也至少知道问题出在哪一层。
最常用的几个命令:
redis-cli -a password ping # 检查连通性 redis-cli -a password DBSIZE # 看当前库有多少 key redis-cli -a password --scan --pattern "user:*" # 按前缀扫 key redis-cli -a password TTL user:10001 # 查剩余过期时间 redis-cli -a password --bigkeys # 找出大 key,线上慎用,测试环境很好用--bigkeys命令会扫描全库并统计占用空间最大的 key。我建议只在测试环境或者业务低峰期使用,因为全量扫描对实例还是有一定压力的。
顺便解释一下SELECT 0。Redis 默认有 16 个逻辑数据库(索引 0-15),你可以把它们理解成同一个 Redis 服务里的 16 个独立命名空间。但我在生产环境几乎只用 db0,多个业务需要隔离时,优先用不同的 Redis 实例或 key 前缀,而不是切换 db。db 隔离并不能真正隔离资源,一个业务的大 key 和慢查询同样会拖慢其他业务。
4.2 Redis Desktop Manager 和 Another Redis Desktop Manager 怎么选
图形客户端是很多人第一次接触 Redis 时最熟悉的入口。网上搜“Redis Desktop Manager”会得到两款容易被搞混的软件:
- 老牌的 Redis Desktop Manager(RDM):界面成熟,但有授权收费版本,免费版可用功能和弹窗限制比较多。
- Another Redis Desktop Manager(ARDM):另一个开源项目,UI 风格偏现代,支持 key 模糊搜索、JSON 格式化、多连接管理,GitHub 上星标很多,平时自己练手完全够用。
我用 ARDM 最常用的功能有三个:全局搜索 key,不管 key 在哪个库都能快速找到;内置命令行面板,选中 key 后直接跑命令,比只点点点灵活;值预览的自动格式化,能看到字符串内容,遇到 JSON 还能格式化展示,省得自己复制出去看。
图形工具也有一个共性缺点:连生产环境一定要谨慎。千万不要用 GUI 客户端顺手执行 FLUSHALL 这种命令,尤其在一个窗口里开了多个连接时,鼠标点错实例是真实发生过的悲剧。我自己的习惯是:生产环境只开命令行会话,图形工具一律只连开发测试环境。
4.3 连接出问题先查这三个方向
不管是 redis-cli 还是图形客户端,连接不上 Redis 时,90% 的原因是三个方向:
- Redis 进程没启动或者端口不对,
ps -ef | grep redis看进程,redis-cli ping试本地。 - 网络不通。云服务器没有放行 6379 端口、防火墙拦截、Docker 端口映射没对。
- 认证没配好。如果报错
NOAUTH Authentication required,就是客户端没带密码或者密码填错了。
我踩过比较久的一个坑是云安全组:明明本地redis-cli ping是通的,但远程机器上的程序连不上,查了很多资料才发现是云控制台里安全组的入站规则只放行了 80,没放行 6379。所以配置 Redis 时,第一件事就是把端口、防火墙、安全组三个层面的放行情况确认好。
5. 进阶:分布式锁、缓存治理与中间件定位
5.1 分布式锁:为什么 SET NX EX 是正确姿势
先不说分布式锁之前,先说清它要解决的问题:多台服务器同时运行同一个任务时,比如定时任务调度、扣减库存,要保证同一时刻只有一个节点在操作临界资源。这个“跨进程的互斥”,在单机里可以用 synchronized 或 lock,但分布式多进程之间,必须有一个大家都能访问到的组件来维护状态,Redis 是使用最广泛的方案之一。
实现方式的关键是:
SET lock:order:10001 "node-A" NX EX 30拆开看:NX表示只有当 key 不存在时才写入,这样多个节点同时执行时,只有一个能 SET 成功,它就是拿锁的赢家;EX 30表示这个锁 key 有 30 秒过期时间,防止拿到锁的节点崩溃后锁永远不释放。
释放锁的时候不能用DEL lock:order:10001就完事,因为存在一种经典误删场景:A 节点拿到锁,处理超过 30 秒导致锁自动过期,B 节点趁机拿到锁,然后 A 处理完直接 DEL,把 B 的锁删了。正确姿势是用 Lua 脚本对比 value 再删:
if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end如果锁里面的 value 是自己写的标识,才执行 DEL;不是自己的锁,就放弃删除。这才是一个合格的 Redis 分布式锁释放流程。
5.2 分布式锁的坑:过期时间、重入、主从切换
初学者以为自己会了SET NX EX解锁分布式锁,其实后面还有几个坑:
第一,锁的过期时间很难拿捏。设短了,业务没处理完锁就过期,另一个节点进来重复执行;设长了,一旦持有锁的节点出问题,其他节点要等很久。实践里通常的做法是:过期时间先给一个基准值,业务代码里再启动一个“续期”任务,比如每过 10 秒就把过期时间重置为 30 秒,直到业务结束才释放锁。Redisson 里的 watchdog 就是这么干的,这也是很多公司直接用 Redisson 的原因。
第二,Redis 分布式锁默认不可重入。同一个线程如果已经持有锁,再次申请时会发现自己拿不到。自己实现的简单锁通常需要额外用 ThreadLocal 计数支持重入,而 Redisson 已经帮你处理了。
第三,主从切换下的锁丢失风险。主节点写入锁后还没同步到从节点,主节点就宕机了,从节点被提升为主节点,此时锁状态不存在,另一个节点就能拿到锁。要彻底解决需要 RedLock 一类的高成本方案,但业界对 RedLock 也有不少争议。我的建议是:如果公司有需求,先考虑能否接受极低概率的重复执行;如果可以接受,普通单节点 + 过期时间就够了,不必为了“听起来完美”引入过重方案。
5.3 缓存治理:穿透、击穿、雪崩,三个高频面试词
这三个词在 Redis 面试题里出现频率极高,确实是缓存治理的核心关注点。把它们当成三种“缓存失效时的故障模式”来理解,比背定义更有效。
- 缓存穿透:查一个一定不存在的 key,缓存没有,数据库也没有,请求每次都打到数据库。如果有人恶意构造不存在的 ID,数据库会被打挂。解决办法:缓存空结果并设置短过期时间;或者在入口做参数校验;更彻底的是用布隆过滤器。
- 缓存击穿:某个热点 key 过期的一瞬间,大量请求同时回源数据库,数据库压力瞬间飙升。解决办法:热点 key 不过期 + 后台更新;或者在查询时加互斥锁,只让一个请求去查库,其他请求等结果回来后再读缓存。
- 缓存雪崩:大量 key 在同一时间过期,或者 Redis 整体不可用,导致所有请求全扑向数据库。解决办法:给过期时间加入随机偏移量,避免同一秒内大量过期;Redis 高可用用主从 + 哨兵,避免单点故障。
这三个问题我自己在项目里都真实见过。最直观的体会就是:缓存不是随便设置 key 就结束,必须考虑“缓存没有值时,系统还能不能扛得住数据库查询”这种兜底场景。
5.4 缓存淘汰策略:内存满了到底淘汰谁
很多新手不知道 Redis 内存是有限度的,配置里可以设置maxmemory,比如 512MB 或 2GB。到达上限后,Redis 会根据maxmemory-policy执行淘汰策略。常用的有:
| 策略 | 行为 | 适合场景 |
|---|---|---|
| noeviction | 不淘汰,写入直接报错 | 缓存不可丢的场景 |
| allkeys-lru | 从所有 key 中选最近最少使用 | 通用缓存场景 |
| volatile-lru | 只从设了过期时间的 key 里淘汰 | 保留永久 key 的混合业务 |
| allkeys-random | 随机淘汰 | 对淘汰结果不敏感 |
| volatile-ttl | 优先淘汰剩余 TTL 最短的 key | 过期时间有明显梯度时 |
我自己的推荐是:纯缓存业务用allkeys-lru,并给各种 key 都设置合理的 TTL;只有当某些 key 必须常驻内存时才考虑volatile-lru。淘汰策略不是越复杂越好,关键是你得知道“数据被淘汰后,业务会不会出问题”。如果缓存里丢的是热点文章,最多多查一次数据库;如果缓存里丢的是用户会话,用户可能被登出,体验就变差。
5.5 缓存与数据库一致性:先更新库再失效缓存
这是缓存治理里最实操的部分。最简单的模式叫 Cache-Aside,流程是:读请求先查缓存,缓存没有则查数据库,再写回缓存;写请求先更新数据库,再删除缓存。
为什么是“删除缓存”而不是“更新缓存”?因为并发场景下,更新缓存容易出现“旧数据覆盖新数据”的问题:有两个写请求先后改了数据库,但它们写缓存的动作可能乱序。删除缓存则更简单,下次读的时候发现缓存没了,会重新查库写缓存,拿到的一定是数据库的最新值。
当然,删除缓存也会遇到中间态问题:线程 A 更新数据库后删缓存,但线程 B 正好在删缓存之前把一次性读到的旧数据写回了缓存,之后缓存里就一直是旧值,直到下次过期。要彻底解决需要引入 binlog 订阅、版本号等方案,但这些在“初步学习”阶段属于进阶内容。掌握“先更新库、再删缓存”这个基本盘,已经能避免 90% 的明显错误。
6. 常见问题排查与学习路线
6.1 Redis command timed out 报错排查思路
网上搜“Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException”的人特别多,这是 Java 项目里用 Lettuce(Spring Boot 默认的 Redis 客户端)执行命令超时了。遇到这个报错,不要急着去调超时时间,先按顺序排查:
- 看 Redis 端是否有慢命令。执行
redis-cli --latency,观察是否持续高延迟。 - 看 Redis CPU 和内存。CPU 打满或者内存被 swap 占用,Redis 处理命令会明显变慢。
- 看是否存在大 key。一个几十 MB 的 key,执行 GET 或 DEL 都可能阻塞 Redis 主线程几百毫秒,期间其他命令全部排队超时。
- 看客户端连接池是否打满。Lettuce 的默认连接池配置不大,如果业务突发流量巨大,线程在池子里等待就会超时。
如果是慢命令导致的超时,执行SLOWLOG GET 10查看最近的慢命令日志,确认是哪个 key 的哪种操作耗时最长,再决定是拆分 key、优化数据结构还是限制命令大小。如果是连接池不够,可以适当调大连接配置,但更根本的是要让 Redis 命令本身足够快。
6.2 日志怎么看:从启动日志到慢日志
Redis 的日志信息量很大,但初学者容易忽略。启动日志里最值得看的是版本号、运行模式、持久化状态、端口绑定这些信息。排查性能问题时,慢日志比普通日志更有用。慢日志默认记录超过阈值(通常是 10 毫秒)的命令,把阈值调小一点更适合性能敏感场景:
slowlog-log-slower-than 5000 slowlog-max-len 128这个配置表示超过 5 毫秒的命令都会记录下来。查看时用SLOWLOG GET,每一行会包含执行时间、耗时、命令参数。把慢日志收集起来,基本能定位到绝大多数性能瓶颈。
6.3 大 key 问题诊断
大 key 和超时问题经常一起出现。判断大 key 的标准要结合业务,比如单个 String 值超过几 MB、一个 Hash/List/ZSet 里的元素数量超过万级,都可以当作潜在风险。最直观的影响有两个:第一,操作它的命令本身耗时长,可能阻塞 Redis 主线程;第二,复制和持久化时占带宽和 CPU,甚至导致主从延迟变大。
测试环境可以直接用redis-cli --bigkeys全库扫描。线上环境更推荐用自定义抽样,比如用redis-cli --scan --pattern "某业务前缀:*"逐个确认大 key。如果真的发现大 key,不要直接在主线程执行 DEL,因为在老版本里持键的集合类 key 也会阻塞;可以使用UNLINK命令异步删除,让 Redis 在后台线程释放内存。
6.4 面试常见考点串讲
其实“Redis 初步学习”学完以后,你手里已经攒下了很多面试考点,这里把高频的串一遍:
- RDB 和 AOF 的区别:RDB 是内存快照,恢复速度快但可能丢最后一次快照后的数据;AOF 是命令日志,数据安全度高但文件更大、恢复更慢。生产环境经常两者都开。
- 过期删除策略:惰性删除(访问时检查是否过期)+ 定期删除(周期抽查)。Redis 不会实时把所有过期 key 都删掉,这也是面试常考点。
- 单线程为什么快:内存操作 + IO 多路复用 + 避免锁竞争和上下文切换。
- 缓存一致性:先更新数据库再删缓存。
- 分布式锁:SET NX EX + 通过 Lua 脚本释放锁。
别把面试题看得太重,但知道它们背后的原理,你的 Redis 知识就不再是零散的“会操作”,而是有体系的“懂原理”。
6.5 后续学习路线建议
把“初步学习”收个尾,给几条后续路径:
- 先学会用
OBJECT ENCODING命令查看 key 的底层编码,对 Redis 内部会有直观认识,也能加深对内存优化的理解。 - 继续学发布订阅 / Stream 消息,理解 Redis 做中间件的更多玩法。
- 再进一步就是 Redis Cluster 集群的搭建和数据分片原理,以及哨兵模式,这已经进入中级阶段。
- 运维方向可以重点学监控指标:INFO 命令的各个分区、MEMORY 命令、慢日志、以及 AOF 和 RDB 的持久化任务分析。
我比较建议用“问题驱动”的方式进阶。比如:我希望缓存更新不丢数据,就去研究 AOF 配置;我担心热点 key 打爆数据库,就去研究缓存击穿方案。一个个真实问题牵引着学,比按目录读官方文档快得多。
最后分享一点实际体会。我见过太多人把“Redis 初步学习”理解为“把命令背熟”,结果遇到 Redis 引发的线上故障时照样手足无措。我觉得真正算“初步学好”的标志,是你能在脑子里迅速建立一条链路:业务要什么数据 -> 这个数据适合用什么 Redis 结构 -> key 怎么命名、TTL 怎么定 -> 缓存丢失后回源数据库会不会出问题 -> 高并发下有没有并发和一致性的坑。这条路走通以后,Redis 对你来说就不再是一个“会跑的服务”,而是真正能支撑业务的中间件。