Redis 线程模型、指令原子性与 BigKey
Redis 系列 · 第 3/10 篇
上一篇:02 核心数据结构 · 下一篇:04 持久化 RDB/AOF
场景:面试必问,生产必懂
「Redis 单线程还是多线程?」「如何保证原子性?」「BigKey 怎么查?」——本文从 2024 年 Redis 定位讲起,梳理线程模型、六种原子性方案与 BigKey 风险。
前置: 单机 Redis 已搭好,建议配置 daemonize yes、protected-mode no、requirepass。
一、Redis 是什么(2024 视角)
Redis = REmote DIctionary Server,高性能 K-V 存储。官方定位三方面:Cache(缓存)、Database(数据库)、Vector Search(向量搜索)。
- 数据结构比传统 K-V 丰富,已超出纯缓存
- 数据在内存,读写极快
- 持久化到磁盘,可当数据库用
2024 生态
- Redis Cloud:基于 AWS/Azure 的企业云服务
- Redis Enterprise:企业收费版
- Redis Insight:官方图形化客户端
- Redis OSS vs Redis Stack:Stack 在 OSS 上叠加 JSON、Search、Bloom 等扩展



二、单线程还是多线程?
整体:客户端多线程,服务端以单线程处理命令为主。
- 连接层:
maxclients(默认 10000)多线程维护 Socket - 命令执行:主线程 + epoll IO 多路复用,请求串行执行 → 无 MySQL 式脏读/幻读,但需自己保证复合逻辑原子性
版本演进:
| 版本 | 特点 |
|---|---|
| 4.x 前 | 纯单线程 |
| 5.x+ | RDB/AOF、unlink、集群同步等放后台线程 |
| 6.x/7.x | 可选 IO 线程加速读写 |
Redis 刻意保持命令执行单线程:CPU 通常不是瓶颈(内存/网络才是);多线程命令执行会增加锁竞争与复杂度。

三、指令原子性
单客户端内命令串行,但多客户端并发时,复合操作需额外机制。

1. 复合命令
MSET、GETSET、SETNX、SETEX 等单条命令原子。
2. Redis 事务
MULTI
set k2 2
incr k2
get k2
EXEC # 或 DISCARD 放弃
WATCH key [...] # 监听 key,变化则 EXEC 失败与 DB 事务不同: 不支持回滚;某条命令类型错误(如 LPOP 作用于 string)只该条报错,其余仍执行。作用仅是打包排队,不被其他客户端插队。
要点:
- WATCH:仅当前客户端
UNWATCH有效 - 失败:EXEC 前语法错 → 整组不执行;EXEC 后类型错 → 其他命令照常
- 宕机:EXEC 后先写 AOF 再执行,崩溃可能导致 AOF 与数据不一致,需
redis-check-aof修复 - 适用:简单批量、对强一致要求不高的场景


3. Pipeline
cat command.txt | redis-cli -a pwd --pipe
# command.txt: set count 1 / incr count ...作用: 打包多条命令,减少 RTT,提升批量写入吞吐。
注意: 非原子;可能与其他客户端命令交错;不宜拼装过多命令以免阻塞客户端。



4. Lua 脚本
Lua 单线程语义,在 Redis 服务端执行天然原子。
EVAL "local v=redis.call('get',KEYS[1]) ..." 1 stock_1 10KEYS[]/ARGV[]传参redis.call()调 Redis 命令- 默认
lua-time-limit5000ms,超时返回 BUSY - Redis 7 支持只读脚本
EVAL_RO,可卸载到从节点
5. Redis Function(7+)
预加载服务端函数,客户端 FCALL 调用,支持嵌套复用(优于一次性 EVAL 脚本)。
cat mylib.lua | redis-cli -x FUNCTION LOAD REPLACE
FCALL my_hset 1 myhash field value ...集群内需各节点分别加载 Function。
6. 方案选型
| 机制 | 原子性 | 典型场景 |
|---|---|---|
| 复合命令 | 是 | 简单组合 |
| 事务 | 打包非回滚 | 批量写入 |
| Pipeline | 否 | 非热点大批量导入 |
| Lua / Function | 是 | 高并发库存、限流、分布式逻辑 |
生产首选 Lua;其他方案需知局限以便选型。
四、BigKey 问题
BigKey:占用空间极大的 key(如 200 万元素的 list、大 string)。
基于单线程模型,BigKey 易导致阻塞。排查:
redis-cli --bigkeys
redis-cli --memkeys处理策略在缓存设计篇详述(拆分、渐进删除、UNLINK 等)。
五、线程模型总结
- 连接多线程 + 命令单线程 → 并发问题简单,但需选对原子性工具
- 单线程模型不利于吃满多核,Pipeline、Cluster 分片、IO 线程是补充
- 使用 Redis 时始终思考:命令是否会阻塞主线程、是否原子