Redis 常见面试题
→ 返回 面试
Redis:内存 KV,单线程执行命令(6.0+ IO 多线程),常用于缓存、锁、限流、排行榜。详解 Redis。
基础
| 点 | 说明 |
|---|---|
| 单线程命令 | 无锁竞争,CPU 不是瓶颈;慢的是 IO/大 key |
| 6.0+ | 网络 IO 多线程,命令仍单线程 |
| 持久化 | RDB 快照 + AOF 日志;生产 混合 aof-use-rdb-preamble |
| 过期 | 惰性删除 + 定期抽样;maxmemory-policy 淘汰 |
五大数据结构(场景)
| 类型 | 底层/int | 典型场景 |
|---|---|---|
| String | SDS | 缓存、计数、SET NX 锁 |
| Hash | 压缩列表/哈希表 | 对象字段、购物车 |
| List | quicklist | 队列、时间线 |
| Set | intset/哈希表 | 去重、共同好友 |
| ZSet | skiplist + 哈希 | 排行榜、延迟队列 |
扩展:Bitmap、HyperLogLog、GEO、Stream(消费组,轻量 MQ)。
持久化 RDB vs AOF
| RDB | AOF | |
|---|---|---|
| 方式 | 子进程快照 | 追加写命令 |
| 恢复 | 快 | 慢(可重写 shrink) |
| 丢数据 | 两次快照间 | everysec 最多 1s |
| 生产 | 混合持久化推荐 | appendfsync everysec |
高可用
单机 → 主从复制 → Sentinel 故障转移 → Cluster 分片(16384 slot)
| 形态 | 适用 |
|---|---|
| 主从 + Sentinel | 中小规模、自动 failover |
| Cluster | 大数据量水平扩展 |
脑裂:旧主仍可写导致双主;min-replicas-to-write 等缓解。
缓存三大问题
| 问题 | 现象 | 方案 |
|---|---|---|
| 穿透 | 查不存在 key,打穿 DB | 布隆过滤器、空值短 TTL |
| 击穿 | 热点 key 过期瞬间并发回源 | 互斥锁、逻辑过期、热点不过期 |
| 雪崩 | 大量 key 同时过期 / Redis 宕机 | TTL 随机、集群、降级、预热 |
Cache Aside(旁路缓存)
读:Redis → miss → DB → 写 Redis
写:更新 DB → **删除** Redis(非双写)
| 坑 | 说明 |
|---|---|
| DB 成功、删缓存失败 | Binlog/Canal → MQ 重试删除 + TTL 兜底 |
| 慢读回填旧值 | 版本号、热点互斥重建、CDC 再删 |
| MySQL/Redis 副本延迟 | 写后读主或等待复制位点;普通读接受最终一致 |
多级:Caffeine(本地)→ Redis → DB,本地需失效广播。
详见 缓存与一致性。
分布式锁
SET lock:order:1001 <uuid> NX EX 30value 必须是本次请求唯一 token。释放须原子比较所有权:Redis 8.4+ 可用 DELEX ... IFEQ token,旧版本用 Lua 比对 value 再 DEL。
| 问题 | 方案 |
|---|---|
| 业务未完成锁过期 | Redisson 看门狗续期 |
| 可重入 | Redisson RLock |
| GC 暂停后陈旧写 | fencing token,资源端拒绝旧 token |
| 主从切换丢锁 | 副本确认降低风险;WAIT 仍非强一致;Redlock 有边界 |
| 锁与 DB | 先持锁,再开事务,事务提交后解锁;最终靠唯一约束/状态机 |
| 锁与幂等 | 锁只限制同时进入,不能阻止稍后重试;仍需 requestId 去重 |
Redis 单线程为什么快
- 内存操作
- IO 多路复用(epoll)
- 数据结构高效
- 避免线程切换与锁
“单线程”只指核心命令执行,不代表进程只有一个线程:
| 执行单元 | 职责 |
|---|---|
| 主线程 | 事件循环、串行执行命令、修改键空间 |
| Redis 6.0+ I/O threads | 并行 socket 读写;不并行执行普通命令 |
| BIO threads | AOF fsync、异步 close、lazy free |
| RDB/AOF child process | 快照与重写,属于子进程而非线程池 |
客户端也要区分:Lettuce native connection 线程安全,普通命令通常可共享;Jedis 单连接不可跨线程共享,常用 JedisPool;Redisson 的 Netty threads、回调 threads、命令连接池和订阅池不是同一个配置。阻塞命令、事务和 Pub/Sub 应使用专用连接。
Redis vs Memcached
| Redis | Memcached | |
|---|---|---|
| 类型 | 多数据结构 | 仅 String |
| 持久化 | RDB/AOF | 无 |
| 集群 | Cluster | 客户端分片 |
| 线程 | 单线程命令 | 多线程 |
Redis 事务
MULTI / EXEC:不支持回滚;命令排队一次执行;非 ACID 隔离(无隔离级别)。
Cluster 下多 key 事务须 同一 hash slot({tag} 哈希标签)。
常见面试题
Q:Redis 和 MySQL 怎么保证一致?
A:Cache Aside + 删缓存;接受最终一致;强一致用 Canal/MQ 刷缓存或读主。
Q:SET NX 和 Redlock?
A:单实例 SET NX EX + Lua 够用多数场景;Redlock 多主过半,理论有争议。
Q:热 key 怎么办?
A:本地缓存、多副本(写随机 suffix 读聚合)、拆分、限流。
Q:BigKey 危害?
A:阻塞单线程、慢查询、迁移失败;拆分、压缩、异步删 UNLINK。
Q:Stream 和 List 做队列?
A:Stream 支持消费组、ACK、Pending;List 简单但无原生消费组。