# 27. Redis 使用的是哪种内存模型,如何支持高并发的写入与读取?
# 标准答案
Redis 采用 基于内存(In-Memory)的数据存储模型,主要依赖 跳表(SkipList)、哈希表(HashTable)、压缩列表(ZipList)和整数集合(IntSet) 等数据结构进行存储。为了支持高并发访问,Redis 采用了 单线程事件循环(Reactor 模型) 处理客户端请求,基于 I/O 多路复用(epoll/kqueue) 机制,实现了 高效的非阻塞并发处理。
此外,Redis 通过 多种数据结构优化、流水线(Pipeline)、持久化(AOF/RDB)、复制与分片 来提高读写吞吐量,同时利用 乐观锁(CAS)、复制偏移量、延迟队列 等机制来保证一致性。
# 答案解析
# 1️⃣ Redis 采用的内存存储模型
Redis 是 纯内存数据库,其数据模型主要基于 键值存储(Key-Value Store),但其值(Value)不仅限于字符串,还支持丰富的数据结构,如 列表、集合、有序集合、哈希等。底层数据存储依赖 多种优化过的数据结构,以提高查询和修改的效率:
数据结构 | 适用场景 | 主要特性 |
---|---|---|
SDS(简单动态字符串) | 存储字符串 | 变长字符串,减少内存碎片 |
哈希表(HashTable) | 字典存储 | O(1) 读写,扩容采用渐进式 rehash |
跳表(SkipList) | 有序集合(SortedSet) | O(logN) 查询,支持范围查找 |
压缩列表(ZipList) | 短哈希表 / 短列表 | 连续内存,减少内存开销 |
整数集合(IntSet) | 小规模整数集合 | 低内存占用,支持自动转换 |
Redis 通过 智能数据结构选择策略 来减少内存占用,例如:
- 小规模 Hash / List / Set 会使用 ZipList 或 IntSet 代替标准数据结构,降低指针开销。
- 哈希表采用渐进式 rehash,避免阻塞操作。
# 2️⃣ Redis 高并发读写的核心机制
Redis 采用 单线程 + I/O 多路复用 处理请求,结合 多种优化技术 来支持高并发:
# 🔹(1)单线程事件循环
Redis 主线程采用单线程处理客户端请求,避免了线程上下文切换、锁竞争等问题,提供了更高的 CPU 缓存命中率,提升了性能。
🔹 为什么单线程反而能高效处理请求?
- Redis 主要是内存操作(O(1) / O(logN)),CPU 不是瓶颈,而是网络 I/O 和系统调用的开销更大。
- 避免多线程锁竞争,减少加锁/解锁的开销,提高 CPU 利用率。
- I/O 多路复用(epoll/kqueue)支持同时处理大量并发连接。
# 🔹(2)I/O 多路复用
Redis 使用 epoll(Linux)或 kqueue(macOS) 进行 非阻塞 I/O 处理:
- 采用 事件驱动机制(Reactor 模型),通过
select/poll/epoll/kqueue
等系统调用来监听多个连接,避免了传统阻塞 I/O 的低效。 - 事件类型包括:可读事件、可写事件、定时任务、文件事件等,采用 事件循环 进行调度。
示例:Linux epoll
监听多个 socket 事件:
epoll_create(); // 创建 epoll 事件监听
epoll_ctl(); // 添加 Redis 客户端 socket 到 epoll
epoll_wait(); // 监听多个事件,减少 CPU 轮询开销
2
3
🔹 优点:
- 减少了 CPU 轮询消耗(不像
select/poll
需要遍历整个事件列表)。 - 避免了线程切换(单线程即可高效处理数万级别的并发连接)。
# 🔹(3)Redis 的读写优化
Redis 采用 数据结构优化 + 异步处理 来提高吞吐量:
机制 | 作用 | 优势 |
---|---|---|
Pipeline(流水线) | 合并多个命令,减少 RTT | 降低网络延迟 |
Lazy-Free(惰性删除) | 异步删除大对象 | 避免阻塞主线程 |
QuickList(快速链表) | 组合 ZipList 和 LinkedList | 减少指针占用,提高缓存命中 |
HyperLogLog | 近似去重 | 仅用 12KB 统计 10 亿级数据 |
# 3️⃣ Redis 在高并发下的读写一致性
# 🔹(1)Redis 复制机制
- 主从复制:采用 异步复制,主节点处理写请求后,异步同步到从节点,提高读吞吐。
- 偏移量控制:主从之间维护 复制偏移量,保证增量同步。
- Gossip 协议:Redis Cluster 通过 Gossip 机制 定期同步元数据,保证数据一致性。
问题:主从切换可能导致数据丢失?
- 解决方案:
WAIT
机制,要求主节点等待至少N
个从节点确认写入后才返回成功。
# 🔹(2)一致性控制
机制 | 作用 | 适用场景 |
---|---|---|
事务(MULTI/EXEC) | 批量执行多个命令,保证原子性 | 适用于小规模事务 |
WATCH 机制 | 监视键值变化,防止并发修改 | 适用于乐观锁场景 |
CAS(Compare-And-Swap) | 结合 GET & SETNX 实现原子更新 | 分布式锁场景 |
示例:使用 WATCH
进行 CAS 操作:
WATCH counter
MULTI
INCR counter
EXEC
2
3
4
如果 counter
发生变更,事务 EXEC
将失败,需重试。
# 4️⃣ Redis 的高并发优化
Redis 采用 数据分片 + 复制 + 多线程 I/O 进行扩展:
- 分片(Sharding):Redis Cluster 采用 哈希槽(Hash Slot)机制 进行数据分布,避免单点瓶颈。
- 多线程 I/O(Redis 6.0+):
- 仅限于 网络 I/O 线程,核心逻辑仍然是单线程。
io-threads
配置 开启多线程,提高网络吞吐:io-threads 4
1- 实测 吞吐量提高 2~3 倍,降低延迟。
# 深入追问
🔹 Redis 为什么采用单线程模型?它的瓶颈在哪?
🔹 Redis 的 epoll
和 Go 语言的 goroutine
调度模型有什么不同?
🔹 Redis 如何处理大对象删除时的阻塞问题?(惰性删除 vs 主动删除)
# 相关面试题
🔹 Redis 为什么单线程还能支撑高并发?
🔹 Redis 如何处理海量 Key 查询的高效索引?
🔹 Redis 的数据淘汰策略有哪些?如何优化内存占用?
# 总结
Redis 采用 基于内存(In-Memory)的数据模型,通过 高效数据结构(哈希表、跳表、压缩列表) 进行存储,并结合 单线程事件循环 + I/O 多路复用 来支持高并发读写。为了进一步优化吞吐,Redis 采用 Pipeline、异步删除、主从复制、分片(Cluster)、多线程 I/O(6.0+) 等技术,确保在高并发场景下依然具备高性能、低延迟 的特点。