Redis 基础与定位
Redis 基础定位
数据服务
内存数据结构服务
缓存系统
分布式状态层
实时计算辅助组件
适合场景
热点读缓存
计数器
排行榜
限流
会话
轻量消息流
地理位置
实时统计
搜索与向量检索
边界
强事务账本
复杂关系查询
长期唯一主存储
大对象堆积
基础命令
SET GET
DEL EXISTS TYPE
EXPIRE TTL PERSIST
SCAN
工程关注
一致性
容量
延迟
故障恢复
安全边界
Redis 是以内存为主的数据结构服务,具备低延迟、高吞吐、丰富数据结构、持久化、高可用和集群扩展能力。它常用于缓存、计数器、排行榜、限流、会话、分布式状态、轻量消息流、地理位置、实时统计、全文搜索、时序数据和向量检索。
Redis 的核心价值不是简单的 SET/GET,而是把合适的数据结构放到合适的业务链路里,并控制好一致性、容量、延迟、故障恢复和安全边界。
| 场景 | 是否适合 | 说明 |
|---|---|---|
| 热点读缓存 | 适合 | 降低数据库压力,提升响应速度 |
| 验证码、短期 token | 适合 | TTL 能天然表达生命周期 |
| 计数器 | 适合 | INCR/INCRBY 原子递增 |
| 排行榜 | 适合 | ZSet 按 score 排序 |
| 接口限流 | 适合 | String、ZSet、Lua 可实现多种限流算法 |
| 分布式会话 | 适合 | TTL、Hash、String 可表达会话状态 |
| 轻量消息流 | 可用 | Stream 支持消费者组、ACK、Pending |
| 分布式锁 | 可用但谨慎 | 必须处理唯一 token、TTL、续期、幂等 |
| 订单账本 | 不适合只用 Redis | 需要强事务、审计、长期一致性 |
| 复杂关系查询 | 不适合 | Redis 不是关系型查询引擎 |
| 长期唯一主存储 | 谨慎 | 持久化、备份、恢复和审计成本高 |
常用基础命令:
| 命令 | 作用 | 使用注意 |
|---|---|---|
SET |
写入字符串 value | 可配合 EX、PX、NX、XX |
GET |
读取字符串 value | 大 value 会带来网络开销 |
DEL |
删除 key | 删除大 key 可能阻塞,优先考虑 UNLINK |
EXISTS |
判断 key 是否存在 | 可用于轻量存在性判断 |
TYPE |
查看 key 类型 | 排查序列化或结构误用 |
EXPIRE |
设置过期时间 | 缓存 key 建议默认有 TTL |
TTL |
查看剩余过期时间 | -1 表示无过期,-2 表示不存在 |
PERSIST |
移除过期时间 | 谨慎使用,避免缓存永久堆积 |
SCAN |
渐进式扫描 key | 生产环境替代 KEYS |
Redis 核心知识
1 Redis 的本质
Redis 是以内存为主、命令模型简单、延迟极低的数据服务。它不是只能做缓存,也可以承担计数、排行榜、限流、分布式状态、会话、消息流、实时统计、搜索和向量检索等任务。
但 Redis 也不是万能数据库。强一致交易、复杂关系查询、长期账本、审计型主存储,不应该只依赖 Redis。
2 数据结构选择
Redis 数据结构
String
对象 JSON 缓存
计数器
验证码
阅读量
分布式锁 value
分布式 ID
Hash
用户对象
购物车
会话字段
局部更新
大 Hash 拆分
List
简单队列
最新列表
阻塞消费
可靠性弱点
Set
去重
抽奖
共同好友
交并差
ZSet
排行榜
延迟队列
滑动窗口限流
范围查询
Bitmap
签到
在线状态
布尔统计
位运算
HyperLogLog
UV
DAU
近似去重
低内存基数估算
Geo
附近门店
附近的人
距离计算
Stream
消息流
消费者组
ACK
Pending
重试
Redis 8 扩展
JSON
TimeSeries
Bloom
Cuckoo
Count-Min Sketch
TopK
TDigest
Vector
| 业务问题 | 推荐结构 | 原因 | 风险 |
|---|---|---|---|
| 对象缓存 | String/Hash/JSON | String 简单,Hash 可局部更新,JSON 支持文档路径 | 大对象和序列化兼容 |
| 购物车 | Hash | 商品到数量/属性的映射自然 | 大 Hash 拆分 |
| 排行榜 | ZSet | score 排序天然适配 | 热点榜单和更新频率 |
| 签到/在线 | Bitmap | 位级存储省内存 | offset 设计 |
| UV | HyperLogLog | 低内存近似去重 | 有误差,不能反查成员 |
| 附近门店 | Geo | 半径查询方便 | 精度和地理边界 |
| 消息流 | Stream | 消费者组、ACK、Pending | 堆积、重试、清理 |
| 延迟任务 | ZSet | score 表示执行时间 | 幂等、并发抢占、死信 |
| 存在性判断 | Bloom/Cuckoo | 空间效率高 | 误判和删除能力 |
| 语义搜索 | Vector/Search | 适合 RAG、推荐、向量检索 | 索引内存和召回率 |
3 数据结构命令与示例
String
String 是最常用的数据结构,适合对象缓存、计数器、验证码、分布式锁 token、分布式 ID。
redis
SET user:1001 '{"id":1001,"name":"Tom"}' EX 3600
GET user:1001
INCR article:read:1001
SET verify:login:13800000000 924681 EX 300
SET lock:order:1001 request-uuid NX PX 30000
String 的 value 不宜过大。大 value 会增加网络传输、序列化、复制和迁移成本。频繁修改局部字段的对象更适合 Hash 或 JSON。
Hash
Hash 适合对象字段、购物车、会话字段等局部更新场景。
redis
HSET user:1001 id 1001 name Tom age 18
HGET user:1001 name
HINCRBY cart:{u1001} sku:2001 1
HGETALL cart:{u1001}
Hash 的优势是字段级读写,缺点是单个 Hash 过大后会形成大 key。购物车、用户属性、会话字段要按用户或业务维度拆分。
List
List 适合简单队列和最新列表。
redis
LPUSH task:queue task-001
RPOP task:queue
BLPOP task:queue 5
LPUSH feed:u1001 item-1 item-2
LRANGE feed:u1001 0 19
List 实现队列很简单,但可靠性弱。任务被弹出后如果消费者宕机,消息可能丢失。可靠消息流更适合 Stream。
Set
Set 适合去重、抽奖、共同好友、集合运算。
redis
SADD follow:u1 u2 u3 u4
SADD follow:u2 u3 u5
SINTER follow:u1 follow:u2
SRANDMEMBER lottery:20260522 10
SREM lottery:20260522 user1001
大集合做交并差运算可能阻塞 Redis。生产中要限制集合大小,或把运算放到异步任务、离线任务中处理。
ZSet
ZSet 适合排行榜、延迟队列、滑动窗口限流。
redis
ZADD rank:game:daily 9800 user1001
ZREVRANGE rank:game:daily 0 9 WITHSCORES
ZADD delay:order 1780000000000 order-1001
ZRANGEBYSCORE delay:order 0 1780000000000 LIMIT 0 100
ZREM delay:order order-1001
ZSet 的核心是 score 设计。排行榜用分数,延迟队列用时间戳,滑动窗口限流用请求时间。
Bitmap
Bitmap 适合签到、在线状态、布尔集合统计。
redis
SETBIT sign:202605:u1001 21 1
GETBIT sign:202605:u1001 21
BITCOUNT sign:202605:u1001
SETBIT online:20260522 1001 1
BITCOUNT online:20260522
Bitmap 的关键是 offset 设计。连续 ID 非常省内存,稀疏 ID 会浪费空间。
HyperLogLog
HyperLogLog 适合 UV、DAU 等近似去重统计。
redis
PFADD uv:20260522 u1 u2 u3
PFCOUNT uv:20260522
PFMERGE uv:week:202605 uv:20260520 uv:20260521 uv:20260522
HyperLogLog 内存占用低,但有误差,不能反查具体成员。需要精确成员列表时应该使用 Set 或数据库。
Geo
Geo 适合附近门店、附近的人、距离计算。
redis
GEOADD shop:geo 116.397128 39.916527 shop1001
GEOSEARCH shop:geo FROMLONLAT 116.40 39.91 BYRADIUS 5 km WITHDIST ASC
GEODIST shop:geo shop1001 shop1002 km
Geo 本质上基于 ZSet 和 geohash。复杂 GIS 分析仍应交给专业地理信息系统。
Stream
Stream 适合轻量消息流、消费者组、削峰和异步处理。
redis
XADD order:stream * orderId 1001 userId u1001
XGROUP CREATE order:stream group-a 0 MKSTREAM
XREADGROUP GROUP group-a c1 COUNT 10 BLOCK 5000 STREAMS order:stream >
XACK order:stream group-a 1680000000000-0
XPENDING order:stream group-a
Stream 要设计 Pending 消息处理、重试次数、死信队列、ACK 后清理策略和幂等消费。它可以承担轻量消息场景,但不能完全替代 Kafka、RocketMQ 这类专业 MQ。
4 缓存工程
缓存工程
Cache Aside
查缓存
未命中查 DB
回填缓存
更新 DB 后删缓存
缓存穿透
参数校验
空值缓存
布隆过滤器
缓存击穿
热点 key 过期
互斥锁
逻辑过期
热点预热
本地缓存兜底
缓存雪崩
大量 key 同时过期
Redis 整体不可用
TTL 抖动
多级缓存
限流
熔断降级
缓存一致性
更新 DB 后删缓存
延迟双删
MQ 补偿
binlog CDC 修复
版本号
短 TTL
热点治理
本地缓存
拆 key
多副本读
请求合并
大 Key 治理
拆分
分页
压缩
UNLINK
| 问题 | 定义 | 解决方案 | 生产注意点 |
|---|---|---|---|
| 缓存穿透 | 查询不存在数据,绕过缓存打 DB | 参数校验、空值缓存、布隆过滤器 | 空值 TTL、误判率 |
| 缓存击穿 | 热点 key 过期,大量请求回源 | 互斥锁、逻辑过期、热点预热 | 锁超时、读旧值、回源失败 |
| 缓存雪崩 | 大量 key 同时失效或 Redis 故障 | TTL 抖动、多级缓存、限流、降级 | DB 保护和故障演练 |
| 数据一致性 | DB 与缓存短暂不一致 | 更新 DB 后删缓存、延迟双删、MQ/CDC 补偿 | 删除失败必须可恢复 |
| 热点问题 | 单 key 承担极高流量 | 本地缓存、拆 key、多副本读、限流 | 防止单节点打满 |
| 大 Key | 单 key value 或集合过大 | 拆分、分页、压缩、UNLINK | 删除、迁移、复制都会变慢 |
5 分布式锁、Lua、事务与 Pipeline
并发与原子能力
分布式锁
SET NX PX
唯一 token
TTL
Lua 释放
续期
Redisson watchdog
业务幂等
Lua
原子脚本
扣库存
限流
安全释放锁
防重复下单
慢脚本阻塞
事务
MULTI
EXEC
DISCARD
WATCH
乐观锁
不支持复杂回滚
Pipeline
减少 RTT
批量读写
非事务原子
控制批量大小
输出缓冲区
Function
脚本版本化
命名加载
生产治理
分布式锁基础命令:
redis
SET lock:order:1001 requestId NX PX 30000
安全释放锁要用 Lua 校验 value:
lua
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
要点:
- value 必须唯一,不能只用业务 ID。
- 锁必须设置 TTL。
- 业务执行时间超过 TTL 时,要续期或重构流程。
- 分布式锁只解决互斥,不解决全部一致性问题。
- Lua 可以保证脚本内原子执行,但慢脚本会阻塞 Redis。
- Pipeline 减少网络 RTT,但不是事务。
- Redis Function 更适合对脚本做版本化和治理。
6 持久化
Redis 持久化
RDB
快照
BGSAVE
文件紧凑
恢复快
可能丢最近数据
AOF
写命令追加
always
everysec
no
数据更完整
文件更大
AOF rewrite
压缩历史命令
rewrite buffer
磁盘 IO
Multi-part AOF
base
incremental
manifest
fork COW
latest_fork_usec
写时复制
内存额外占用
Redis 抖动
THP swap overcommit
生产治理
预留内存
避开高峰 rewrite
备份校验
恢复演练
| 机制 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| RDB | 文件紧凑,恢复快 | 两次快照之间可能丢数据 | 备份、冷恢复 |
| AOF | 数据更完整 | 文件更大,rewrite 有成本 | 更高安全要求 |
| RDB + AOF | 兼顾恢复速度和完整性 | 配置和资源成本更高 | 常见生产选择 |
| Multi-part AOF | base/incr/manifest 分离,降低 rewrite 复杂度 | 仍需关注磁盘和 rewrite | Redis 7+/8.x 生产 |
fork/COW 是持久化和复制中的重要风险。写入越密集,COW 额外内存越高;实例越大,fork 越容易造成抖动。因此生产上要预留内存,避开高峰做 rewrite,并监控 latest_fork_usec。
7 主从、Sentinel 与 Cluster
高可用与集群
主从复制
PSYNC
全量同步
部分重同步
replid
offset
replication backlog
复制延迟
一致性窗口
异步复制丢数据
WAIT
min replicas
业务补偿
Sentinel
监控
主观下线
客观下线
quorum
选主
故障转移
客户端更新 master
Cluster
16384 slots
CRC16
MOVED
ASK
hash tag
reshard
扩容
缩容
数据倾斜
热点槽
跨槽限制
运维风险
slot 迁移延迟
客户端路由缓存
跨 AZ 网络
热点槽
主从复制用于副本冗余和读扩展,但默认异步复制,主节点故障时可能丢失未复制到从节点的数据。WAIT 可以降低风险,但不能替代业务强一致设计。
Sentinel 负责监控和自动故障转移:
- 主观下线。
- 客观下线。
- 选举新 master。
- 让其他 replica 改为复制新 master。
- 通知客户端更新地址。
Cluster 负责水平扩容:
- 数据按 16384 个 slot 分片。
MOVED表示 slot 已迁移,客户端应更新路由。ASK表示 slot 正在迁移,需要临时访问目标节点。- hash tag 可以让多个 key 落到同一个 slot。
- 扩缩容要关注 slot 迁移、热点槽、数据倾斜和跨槽命令。
8 性能排查
性能排查
慢查询
SLOWLOG GET
命令复杂度
慢 Lua
大集合运算
延迟事件
LATENCY DOCTOR
fork 延迟
fsync 延迟
intrinsic latency
内存
INFO memory
MEMORY USAGE
MEMORY STATS
MEMORY DOCTOR
碎片率
evicted_keys
大 Key
redis-cli bigkeys
拆分
压缩
UNLINK
热 Key
代理日志
客户端采样
HOTKEYS
本地缓存
读分散
客户端
CLIENT LIST
connected_clients
blocked_clients
输出缓冲区
重试风暴
压测
redis-benchmark
value 大小
Pipeline
Cluster 模式
线上 Redis 延迟升高时,按以下路径排查:
- 判断范围:单实例、单业务、单命令还是全链路。
- 查慢命令:
SLOWLOG GET。 - 查延迟事件:
LATENCY DOCTOR。 - 查 CPU、网络、磁盘、swap、fork、THP。
- 查内存:
INFO memory、MEMORY STATS、碎片率、淘汰数量。 - 查大 key:
redis-cli --bigkeys、MEMORY USAGE。 - 查热 key:代理日志、客户端采样、Redis 8.6 HOTKEYS。
- 查复制:主从 offset 差值、复制链路状态。
- 查客户端:连接数、blocked clients、输出缓冲区、重试风暴。
- 查 Cluster:slot 倾斜、跨 AZ、热点槽。
生产级 Redis
生产级 Redis
使用边界
缓存
会话
计数
排行榜
限流
轻量消息
强一致账本谨慎
Key 规范
业务域
对象类型
ID
字段
版本
TTL
hash tag
可扫描治理
数据建模
读写比
单 value 大小
key 数量级
热点分布
局部更新
一致性等级
Cluster 兼容
客户端工程
连接池
超时
幂等重试
Pipeline
序列化
熔断
读写隔离
可观测性
QPS
P95 P99
命中率
used_memory
碎片率
evicted_keys
connected_clients
blocked_clients
复制延迟
slowlog
安全治理
ACL
TLS
VPC 内网
危险命令禁用
运维审计
敏感数据
备份加密
容量规划
key 内存
value 内存
元数据
副本倍数
碎片系数
fork COW 预留
增长预留
降级容灾
限流
熔断
本地兜底
只读降级
队列削峰
备份恢复
多 AZ
故障演练
主节点故障
网络分区
磁盘满
AOF 损坏
大 key 删除
热 key 爆发
客户端重试风暴
1 使用边界
| 场景 | 是否适合 | 说明 |
|---|---|---|
| 热点读缓存 | 适合 | 降低 DB 压力,提升响应速度 |
| 验证码/短期 token | 适合 | TTL 天然匹配 |
| 排行榜 | 适合 | ZSet 适配排序 |
| 限流 | 适合 | INCR、ZSet、Lua 可实现 |
| 分布式锁 | 可用但谨慎 | 需要 TTL、唯一 token、续期、幂等 |
| 轻量消息流 | 可用 | Stream 支持消费者组和 ACK |
| 订单账本 | 不适合只用 Redis | 需要强事务和审计 |
| 复杂关系查询 | 不适合 | Redis 不是关系型查询引擎 |
2 Key 规范
推荐格式:
text
业务域:对象类型:{分片ID}:字段:版本
示例:
text
shop:detail:{1001}:v2
user:cart:{u1001}
rank:game:daily:20260522
lock:order:{orderId}
session:{token}
规范要求:
- 能看出业务归属。
- 有明确生命周期。
- Cluster 下合理使用 hash tag。
- 支持版本迁移。
- 方便扫描治理。
3 客户端工程
| 项 | 要求 | 常见错误 |
|---|---|---|
| 连接池 | 限制最大连接,按业务隔离 | 连接无限增长 |
| 超时 | 设置连接、读、写、命令超时 | 默认超时过长 |
| 重试 | 只对幂等操作有限重试 | 非幂等写重复执行 |
| Pipeline | 控制批量大小 | 单批过大导致缓冲区膨胀 |
| 序列化 | 统一格式和版本 | 混用导致兼容问题 |
| 熔断 | Redis 异常时保护 DB | Redis 挂了流量全打 DB |
4 可观测性
| 指标 | 说明 | 告警方向 |
|---|---|---|
| QPS | 总请求量和命令分布 | 突增或突降 |
| P95/P99 | 延迟分位数 | 超过业务 SLO |
| hit rate | 缓存命中率 | 突降导致 DB 压力上升 |
| used_memory | 内存使用 | 接近 maxmemory |
| mem_fragmentation_ratio | 内存碎片率 | 过高需排查 |
| evicted_keys | 淘汰数量 | 持续增长说明容量不足 |
| expired_keys | 过期数量 | 突增可能是 TTL 集中过期 |
| connected_clients | 连接数 | 突增可能连接泄漏 |
| blocked_clients | 阻塞客户端 | 阻塞命令或慢操作 |
| replication lag | 主从复制延迟 | 影响切换数据安全 |
| slowlog | 慢命令 | 大 key、复杂命令、Lua |
5 容量规划
容量估算公式:
text
总内存 = (业务 value 内存 + key 内存 + Redis 对象元数据 + 数据结构额外开销)
* 副本倍数
* 碎片系数
+ fork/COW 预留
+ 增长预留
建议:
- 内存水位常规不超过 70% 到 80%。
- 大实例至少为 fork/COW 预留 20% 到 40%。
- 按 1.2 到 1.5 估算碎片系数。
- 按 3 到 6 个月业务增长预留容量。
- 单实例不要过大,否则 fork、迁移、恢复都会变慢。
6 安全治理
安全基线:
- 禁止公网暴露 Redis。
- 开启 ACL,按应用分用户和命令权限。
- 使用 TLS 或 VPC/专线隔离。
- 禁用或限制
FLUSHALL、FLUSHDB、CONFIG、KEYS等危险命令。 - 运维命令审计。
- 敏感数据避免明文长期存储。
- 备份文件加密并限制访问。
- 升级 Redis 8 前检查新增命令和 ACL 类别。
7 容灾与降级
| 风险 | 方案 |
|---|---|
| Redis 不可用 | 本地缓存兜底、限流、只读降级、默认值返回 |
| DB 被打穿 | 熔断、请求合并、队列削峰、保护开关 |
| 主节点故障 | Sentinel/Cluster 自动切换、客户端重连 |
| 数据丢失 | RDB/AOF、备份恢复、业务补偿 |
| 跨 AZ 网络抖动 | 就近读、减少跨 AZ 热路径、合理部署副本 |
| 热点活动 | 预热、实例隔离、热点 key 拆分、临时扩容 |
典型工程实例
Redis 工程实例
秒杀库存扣减
String 库存
Lua 原子扣减
防超卖
防重复下单
异步落库
库存流水
接口限流
固定窗口
滑动窗口
令牌桶
ZSet
Lua
Redis 故障兜底
延迟队列
ZSet
score 到期时间
到期拉取
并发抢占
重试
死信
商品详情缓存
String
Hash
JSON
Cache Aside
逻辑过期
CDC 删除缓存
分布式会话
token
session
TTL
黑名单
续期
多端登录
分布式 ID
INCR
日期分段
号段模式
组合 ID
Snowflake 对比
| 场景 | 推荐结构/命令 | 核心流程 | 生产治理 |
|---|---|---|---|
| 秒杀库存扣减 | String + Lua | 校验库存、扣减、记录用户下单 | 幂等、防超卖、异步落库、库存流水 |
| 接口限流 | ZSet/String/Lua | 固定窗口、滑动窗口、令牌桶 | key 过期、热点接口、Redis 故障兜底 |
| 延迟队列 | ZSet | score 为执行时间,拉取到期任务 | 并发抢占、重试、死信、幂等 |
| 商品详情缓存 | String/Hash/JSON | 查缓存、查 DB、回填、删缓存 | 穿透、击穿、雪崩、一致性补偿 |
| 分布式会话 | String/Hash | token 到 session 或 userId | 续期、注销黑名单、多端登录 |
| 分布式 ID | INCR/号段 | 全局递增或日期分段 | 单点热点、趋势递增、Snowflake 对比 |
Redis 8.x 与现代能力
Redis 8.x 现代能力
Redis 8.0
统一发行版
Search
JSON
TimeSeries
Bloom
Vector
Hash field 操作
Redis 8.2
Stream 消费组删除增强
Bitmap 新操作
per-slot 指标
Vector Search 优化
Redis 8.4
原子 slot 迁移
MSETEX
DELEX
DIGEST
FT.HYBRID
AOF 尾部自动修复
Redis 8.6
Stream 幂等
HOTKEYS
LRM 淘汰
TLS 证书认证
key memory histograms
AI 搜索
向量检索
RAG 缓存
语义搜索
推荐召回
升级治理
ACL 检查
客户端兼容
持久化兼容
命令行为
回滚演练
| 能力方向 | 核心价值 | 学习重点 |
|---|---|---|
| Redis 8.0 统一发行版 | Search、JSON、TimeSeries、Bloom 等能力进入统一分发 | 不再只把 Redis 看成传统 9 种结构 |
| Redis 8.2 Stream/Bitmap/指标增强 | Stream 消费者组清理、Bitmap 操作和 per-slot 指标增强 | 用 Stream 做业务流时关注 ACK 后清理和集群观测 |
| Redis 8.4 原子 slot 迁移 | Cluster 迁移窗口和可用性是生产重点 | 原子迁移、AOF 尾部修复、MSETEX、FT.HYBRID |
| Redis 8.6 幂等、HOTKEYS、LRM | 热 key、Stream 重复消息、淘汰策略是高频生产痛点 | 热点检测、幂等写入、新淘汰策略 |
| ACL 与升级检查 | Redis 8 集成新数据结构后 ACL 类别更多 | 升级前检查 ACL、模块、客户端、持久化和命令兼容 |
| AI/搜索场景 | Redis 已扩展到向量检索、全文检索、RAG 缓存 | Vector、Search、JSON、向量索引和召回边界 |
Redis 高频面试题
Redis 面试体系
基础类
数据结构
String 与 Hash
key 过期
缓存价值
缓存类
穿透
击穿
雪崩
MySQL 一致性
先更新 DB 再删缓存
并发类
分布式锁
Lua 释放锁
Redisson watchdog
事务与 Lua
架构类
Redis 为什么快
单线程边界
RDB AOF
主从复制
Sentinel
Cluster
hash slot
hash tag
性能类
大 Key
热 Key
慢查询
Pipeline
淘汰策略
专家类
容量规划
fork COW 抖动
主从切换丢数据
Cluster 扩容迁移
Redis 做 MQ
线上延迟排查
监控告警
源码阻塞
内存碎片
Function
令牌桶
答题结构
定义
原理
方案
边界
生产经验
1 37 道面试题分类
| 类别 | 典型问题 | 答题核心 |
|---|---|---|
| 基础类 | 数据结构、String 和 Hash、过期删除、缓存价值 | 结构、命令、复杂度、适用场景 |
| 缓存类 | 穿透、击穿、雪崩、一致性、删除缓存顺序 | 定义、方案、失败补偿 |
| 并发类 | 分布式锁、Lua、watchdog、事务和 Lua | 原子性、锁安全、幂等 |
| 架构类 | RDB/AOF、主从、Sentinel、Cluster | 流程、风险窗口、运维注意 |
| 性能类 | 大 Key、热 Key、慢查询、Pipeline、淘汰 | 识别、影响、治理 |
| 专家类 | 容量规划、COW、切换丢数据、扩容迁移、源码阻塞 | 生产经验、指标、取舍 |
2 五层答题模板
每道 Redis 面试题建议按五层回答:
- 定义:先说这个问题是什么。
- 原理:说明 Redis 内部为什么会出现这个现象。
- 方案:给出 2 到 4 种解决方案。
- 边界:说明方案代价、失败场景和不适用条件。
- 生产经验:给出监控指标、容量规划、演练或真实工程注意点。
示例:缓存击穿。
| 层次 | 回答要点 |
|---|---|
| 定义 | 热点 key 过期瞬间,大量请求同时回源 DB |
| 原理 | Redis 未命中后所有请求都进入 DB,DB 承接并发峰值 |
| 方案 | 互斥锁、逻辑过期、热点预热、本地缓存 |
| 边界 | 锁过期、回源失败、逻辑过期短暂读旧值 |
| 生产经验 | 监控热点 key、命中率、DB QPS、P99;预案包括限流和降级 |
3 37 道高频题答案
1. Redis 支持哪些数据结构?
Redis 传统核心结构包括 String、Hash、List、Set、ZSet、Bitmap、HyperLogLog、Geo、Stream。String 适合对象缓存和计数;Hash 适合对象字段;List 适合简单队列;Set 适合去重和集合运算;ZSet 适合排行榜、延迟队列和滑动窗口;Bitmap 适合签到和在线状态;HyperLogLog 适合 UV 近似统计;Geo 适合附近位置查询;Stream 适合消费者组消息流。Redis 8 还把 JSON、Search、TimeSeries、Bloom、Vector 等能力纳入统一分发。
2. String 和 Hash 存对象有什么区别?
String 存 JSON 简单,读写整个对象方便,适合展示型缓存。Hash 支持字段级读写,适合购物车、会话、用户属性这类局部更新场景。String 的缺点是改字段要整体序列化,Hash 的缺点是字段过多会形成大 key。复杂文档和路径级更新可以考虑 Redis JSON。
3. Redis 的 key 过期后会立即删除吗?
不会保证立即删除。Redis 使用惰性删除和定期删除结合:访问 key 时发现过期会删除;后台周期抽样删除过期 key。大量 key 同时过期可能造成抖动,所以缓存 TTL 应加随机值,避免集中失效。
4. Redis 为什么适合做缓存?
Redis 基于内存访问,命令模型简单,延迟低,支持 TTL、丰富数据结构、持久化、高可用和集群扩展。它能承接热点读流量,降低数据库压力。缓存系统要同时处理命中率、穿透、击穿、雪崩、一致性和 Redis 故障降级。
5. 什么是缓存穿透?怎么解决?
缓存穿透是查询不存在的数据,请求绕过缓存持续打到数据库。解决方案包括参数校验、缓存空值、布隆过滤器。空值缓存要设置短 TTL,避免无效数据堆积;布隆过滤器有误判率,适合存在性判断,不适合需要删除频繁的场景。
6. 什么是缓存击穿?怎么解决?
缓存击穿是热点 key 过期瞬间,大量请求同时回源数据库。常见方案是互斥锁、逻辑过期、热点预热、本地缓存。互斥锁要控制锁超时和回源失败;逻辑过期允许短暂读旧值,但能保护数据库。
7. 什么是缓存雪崩?怎么解决?
缓存雪崩是大量 key 同时失效,或 Redis 整体不可用,导致请求集中打到数据库。解决方案包括 TTL 随机抖动、分批预热、多级缓存、限流、熔断、降级、Redis 高可用部署和故障演练。
8. Redis 和 MySQL 如何保证数据一致性?
常用策略是先更新数据库,再删除缓存。删除失败时要通过 MQ、binlog/CDC、重试任务修复。强一致场景不要只依赖缓存;缓存一般追求最终一致。对热点数据可使用版本号、短 TTL、延迟双删、逻辑过期降低脏读窗口。
9. 为什么常用"先更新数据库,再删除缓存"?
数据库是最终事实源,先更新数据库能保证主存储正确。删除缓存后,下一次读请求会回源数据库并回填新值。如果先删缓存再更新数据库,可能在更新数据库前被并发读请求回填旧值。删除缓存失败必须有重试或 CDC 修复机制。
10. Redis 分布式锁如何实现?
基础实现是 SET lock:key requestId NX PX timeout。NX 保证互斥,PX 防止死锁,requestId 保证释放时只删自己的锁。释放锁必须用 Lua 判断 value 后删除。业务耗时超过锁 TTL 时,需要续期机制或重构为幂等流程。
11. 为什么释放锁要用 Lua?
释放锁需要"判断 value 是否一致"和"删除 key"两个动作原子执行。如果先 GET 再 DEL,锁可能在两条命令之间过期并被别人获取,导致误删他人的锁。Lua 在 Redis 内单线程原子执行,可以避免这个竞态。
12. Redisson 的看门狗机制是什么?
看门狗是锁自动续期机制。线程持有锁且业务未完成时,Redisson 会周期性延长锁 TTL,避免业务执行时间超过初始锁过期时间导致锁提前释放。它解决锁过早过期问题,但不能替代业务幂等,也不能解决 Redis 故障和网络分区带来的所有一致性问题。
13. Redis 事务和 Lua 有什么区别?
Redis 事务通过 MULTI/EXEC 批量执行命令,配合 WATCH 可做乐观锁,但不支持传统数据库那种复杂回滚。Lua 脚本把逻辑放到 Redis 内部一次执行,原子性更强,适合扣库存、限流、释放锁等场景。Lua 脚本不能太慢,否则会阻塞 Redis。
14. Redis 为什么快?
Redis 快来自内存访问、单线程命令执行减少锁竞争、I/O 多路复用、高效数据结构和紧凑编码。它快的前提是命令足够轻、数据结构合理、没有大 key、慢 Lua、集中 fsync、fork/COW 抖动或网络瓶颈。
15. Redis 真的是单线程吗?
Redis 核心命令执行通常是单线程模型,但后台任务、持久化、异步删除、I/O threads 等不是完全单线程。I/O threads 主要处理网络读写和协议解析,不能理解成所有命令并行执行。慢命令仍然会阻塞主执行路径。
16. RDB 和 AOF 有什么区别?
RDB 是快照,文件紧凑、恢复快,但可能丢失两次快照之间的数据。AOF 记录写命令,数据更完整,但文件更大,rewrite 和 fsync 有成本。生产常用 RDB + AOF 组合,并关注 fork/COW、磁盘 I/O、恢复时间和备份校验。
17. 主从复制的过程是什么?
从节点连接主节点后发送 PSYNC。如果 replid 和 offset 可衔接,执行部分重同步;否则主节点生成 RDB 进行全量同步,同步期间的增量写入保存在 replication backlog。全量加载完成后,从节点继续接收增量命令。
18. Sentinel 如何实现故障转移?
Sentinel 持续监控 master 和 replica。单个 Sentinel 判断不可达是主观下线,多个 Sentinel 达成 quorum 后是客观下线。随后 Sentinel 选举 leader,挑选合适 replica 提升为 master,并让其他 replica 改为复制新 master,客户端再更新 master 地址。
19. Redis Cluster 如何分片?
Redis Cluster 使用 16384 个 hash slot。key 经过 CRC16 计算后映射到 slot,slot 分布在不同 master 上。客户端根据 slot 路由请求。slot 迁移时会出现 MOVED 或 ASK 重定向。Cluster 扩缩容的本质是迁移 slot。
20. 什么是 hash slot?
hash slot 是 Redis Cluster 的逻辑分片单位,共 16384 个。每个 key 属于一个 slot,每个 master 持有一部分 slot。slot 让数据迁移和节点扩缩容可以按槽位进行,而不是按单个 key 手工分配。
21. 什么是 hash tag?
hash tag 是 key 中 {} 内的内容,Redis Cluster 只对这部分计算 slot。例如 cart:{u1001} 和 order:{u1001} 会落到同一个 slot。它适合多 key 同槽操作,但滥用会造成热点槽和数据倾斜。
22. 什么是大 Key?有什么危害?
大 Key 指单个 key 的 value 很大,或集合成员很多。危害包括网络传输慢、序列化慢、删除阻塞、复制慢、迁移慢、内存碎片和单点热点。治理方式包括拆分、分页、压缩、限制 value 大小、用 UNLINK 异步删除。
23. 什么是热 Key?怎么解决?
热 Key 是被极高频访问的 key,会打满单节点 CPU、网络或输出缓冲区。识别方式包括代理日志、客户端采样、监控、Redis 8.6 HOTKEYS。解决方式包括本地缓存、多副本读、拆 key、请求合并、限流和业务降级。
24. Redis 慢查询如何排查?
先用 SLOWLOG GET 查看慢命令,再结合 LATENCY DOCTOR、INFO、MEMORY STATS、客户端日志和系统指标。常见根因包括大 key、复杂集合运算、慢 Lua、AOF fsync、fork/COW、网络抖动、输出缓冲区堆积、客户端重试风暴。
25. Pipeline 有什么作用?
Pipeline 把多条命令一次发送给 Redis,减少网络 RTT,适合批量读写。它不保证事务原子性,也不保证中间命令失败整体回滚。批量过大可能导致客户端内存和 Redis 输出缓冲区压力,要控制单批大小。
26. Redis 内存淘汰策略有哪些?
常见策略包括 noeviction、allkeys-lru、volatile-lru、allkeys-lfu、volatile-lfu、allkeys-random、volatile-random、volatile-ttl,Redis 8.6 还有 LRM 方向。缓存场景常选 allkeys-lru 或 allkeys-lfu,不能丢数据的状态场景应谨慎使用淘汰。
27. 如何做 Redis 容量规划?
容量要估算 key 数量、value 大小、对象元数据、数据结构额外开销、副本倍数、碎片系数、fork/COW 预留和业务增长。常规内存水位不建议超过 70% 到 80%。还要估算峰值 QPS、连接数、网络带宽、持久化磁盘和恢复时间。
28. RDB 或 AOF rewrite 为什么可能导致 Redis 抖动?
RDB 和 AOF rewrite 会触发 fork。fork 大实例可能耗时较长;fork 后如果主进程持续写入,会产生 COW 内存复制;rewrite 还会带来磁盘 I/O。THP、swap、内存不足、磁盘繁忙都会放大抖动。
29. Redis 主从切换会丢数据吗?
可能会。Redis 主从复制默认异步,master 写成功但还没复制到 replica 时,如果 master 故障,新 master 可能没有这部分数据。WAIT、min-replicas-to-write 可以降低风险,但不能彻底替代业务层幂等、补偿和强一致数据库。
30. Redis Cluster 扩容和迁移时要注意什么?
要关注 slot 迁移计划、热点槽、数据倾斜、客户端 MOVED/ASK 处理、迁移期间延迟、跨槽命令、hash tag 分布、备份和回滚。迁移前应压测和演练,迁移中要监控 P99、网络、CPU、复制延迟和失败重试。
31. Redis 可以当消息队列吗?
可以承担轻量消息场景。List 简单但可靠性弱;Pub/Sub 实时但不持久;Stream 支持消费者组、ACK、Pending 和重试,更适合业务消息流。但 Redis 不适合替代 Kafka/RocketMQ 的超大吞吐、长时间堆积、复杂顺序和完善治理场景。
32. Redis 线上延迟突然升高,如何系统排查?
先确认范围,再查慢命令、延迟事件、CPU、网络、磁盘、fork、AOF、内存碎片、大 key、热 key、复制延迟、连接数、blocked clients、输出缓冲区、客户端重试和 Cluster slot 倾斜。止血手段包括限流、熔断、暂停批任务、拆热点、扩容和回滚发布。
33. 如何设计 Redis 的生产监控和告警?
核心指标包括 QPS、P95/P99、错误率、命中率、used_memory、碎片率、evicted_keys、expired_keys、connected_clients、blocked_clients、slowlog、复制延迟、AOF/RDB 状态、CPU、网络、磁盘。告警要配 Runbook,明确第一动作、排查命令和降级方案。
34. 如何从源码角度解释 Redis 命令为什么会阻塞?
Redis 命令在事件循环中执行,命令执行线程处理请求时如果遇到复杂命令、大集合遍历、大 key 删除、慢 Lua、同步磁盘操作或阻塞型操作,就会占用主执行路径,导致后续命令排队。源码阅读可从事件循环、命令表、对象编码、持久化和网络处理入手。
35. 什么是 Redis 内存碎片?如何处理?
内存碎片是 Redis 申请的内存和实际存储数据之间存在差距,常由频繁申请释放、不同大小对象混合、大 key 变化引起。通过 INFO memory、MEMORY STATS 查看碎片率。处理方式包括 active defrag、重启迁移、拆分大 key、稳定对象大小和控制内存水位。
36. Redis Function 和 Lua EVAL 有什么区别?
Lua EVAL 是临时执行脚本,适合快速实现原子逻辑。Redis Function 支持函数加载、命名、版本化和更好的治理,更适合生产中复用脚本逻辑。Function 仍要控制执行时间,避免阻塞 Redis。
37. 如何用 Redis 实现令牌桶限流?
令牌桶需要记录当前令牌数和上次补充时间。每次请求用 Lua 原子计算应补充的令牌、更新桶状态、判断是否允许通过。可以用 Hash 存 tokens 和 last_refill_time。要设置 key TTL,避免无访问用户长期占用内存;Redis 故障时要有本地限流或默认策略。
学习路线
| 阶段 | 学习目标 | 必做练习 | 验收标准 |
|---|---|---|---|
| 第一阶段 | 会用 Redis 基础结构 | 用 String/Hash/List/Set/ZSet/Bitmap/HLL/Geo/Stream 各写一个例子 | 能说清结构、命令、复杂度和场景 |
| 第二阶段 | 会做缓存工程 | 实现商品详情缓存、穿透保护、击穿保护、TTL 抖动 | 能解释一致性和失败补偿 |
| 第三阶段 | 会处理并发 | 实现 Lua 扣库存、分布式锁、滑动窗口限流、延迟队列 | 能解释原子性、幂等和重试 |
| 第四阶段 | 懂 Redis 原理 | 对比 RDB/AOF、复制、Sentinel、Cluster、淘汰、过期 | 能画出复制和 Cluster 迁移流程 |
| 第五阶段 | 会排查性能 | 使用 SLOWLOG、LATENCY、MEMORY、big key 扫描、benchmark | 能给出线上延迟升高排查路径 |
| 第六阶段 | 会做生产架构 | 完成容量估算、监控告警、ACL、安全、备份恢复、演练 | 能独立设计生产 Redis 方案 |
| 第七阶段 | 跟进新版本 | 学习 Redis 8.x Search/JSON/TimeSeries/Vector/Stream/Cluster 增强 | 能判断新能力适用边界 |
知识主线
Redis 学习最终要形成一条完整链路:
text
数据结构 -> 缓存工程 -> 并发控制 -> 原理架构 -> 高可用集群 -> 性能排查 -> 生产治理 -> 面试表达 -> 项目落地
最重要的不是背命令,而是能把每个能力放到真实工程里:
- 数据结构解决"怎么存"。
- 缓存工程解决"怎么抗流量"。
- Lua、锁、事务、Pipeline 解决"怎么保证原子性和效率"。
- 持久化、复制、Sentinel、Cluster 解决"怎么可恢复、可切换、可扩容"。
- 慢查询、内存、延迟、大 Key、热 Key 解决"怎么排障"。
- Key 规范、容量、安全、观测、容灾解决"怎么生产可用"。
- Redis 8.x 扩展能力解决"怎么承接搜索、时序、概率统计和向量检索等现代场景"。