欢迎来到窥视未来的博客

https://github.com/lwx57280 https://gitee.com/li_VillageHead

Redis为什么这么快?——从单线程模型到IO多路复

Redis为什么这么快?——从单线程模型到IO多路复用

与MySQL等传统数据库不同,Redis能以每秒十万级的吞吐量处理请求,延迟低至微秒级。它没有使用多线程和复杂的锁机制,却依然能轻松应对高并发。这背后究竟隐藏着哪些设计哲学?本文从内存操作、单线程模型、IO多路复用、高效数据结构四个维度,深度剖析Redis高性能的底层密码。

一、引言:Redis快在哪里?

先看一组直观的数据(单实例,不做任何特殊优化):

  • 纯内存读写:100ns 级别

  • 网络IO + 命令执行:10μs ~ 100μs 级别

  • QPS:10万+(甚至更高)

与磁盘数据库(如MySQL)相比,Redis快几个数量级。这并非因为硬件差异,而是源于其为速度而生的架构设计

diagram-flowchart (1)

 

 

 

Redis基本特性

  • 速度快

  • 网络模型,IO多路复用

  • 支持多种数据类型

  • 支持多种编程语言

  • 持久化、内存淘汰

  • 功能丰富:事务、发布订阅、pipeline、lua

  • 集群、分布式

二、第一级火箭:纯内存操作

Redis将所有数据存储在内存中,读写操作不涉及磁盘I/O。内存的访问速度是纳秒级,而磁盘是毫秒级,两者相差数万倍。

Redis为什么敢全内存?

  • 业务场景决定:缓存、计数器、实时排行榜等对速度要求极高,对数据量要求相对可控。

  • 持久化保障:RDB + AOF 将内存数据异步落盘,兼顾性能与安全。

  • 内存成本下降:现代服务器内存可达数百GB,足以承载TB级业务数据。

// 伪代码:Redis内存访问
value = dictFind(key);  // 直接内存哈希表查找
return value;            // 无磁盘I/O

三、第二级火箭:单线程模型 —— 化繁为简

3.1 “单线程”到底指什么?

Redis的“单线程”主要指网络IO和命令执行使用同一个线程完成。但并非真的只有一个线程:后台有RDB持久化线程、AOF重写线程、异步删除线程等。

diagram-flowchart (2)

 

 

 

3.2 单线程带来了什么好处?

 
问题多线程模型Redis单线程模型
上下文切换 频繁,开销大(~μs级别)
锁竞争 需要各种锁(互斥锁、读写锁),增加延迟 无需锁
并发复杂度 高,易出现死锁、数据竞争 极低
CPU缓存亲和性 频繁切换导致缓存失效 始终保持高热缓存

为什么单线程还能支持高并发?

因为Redis的瓶颈不在CPU,而在网络IO和内存。单线程配合非阻塞IO,可以轻松达到10万QPS。当需要更多CPU核心时,可以通过Redis Cluster或多实例部署来横向扩展。

四、第三级火箭:IO多路复用 —— 一个线程管理万级连接

4.1 传统阻塞IO的困境

如果每个客户端连接都由一个独立线程处理,那么当连接数达到上万时,线程切换开销将压垮系统。这就是著名的 C10K问题

 

diagram-flowchart (3)

 

 

4.2 IO多路复用:一个线程监听所有连接

Redis使用操作系统提供的 IO多路复用 机制(Linux下为epoll),让一个线程能同时监听成千上万个套接字的读写事件。

epoll的核心工作流程

diagram-flowchart

 

epoll vs select/poll 的优势

  • 无上限:epoll可监听的fd数量只受操作系统限制(通常数十万)。

  • 事件驱动:只返回活跃的fd,无需遍历所有连接。

  • 内存映射:内核与用户空间共享一块内存,减少数据拷贝。

// Redis 事件循环中的 epoll 轮询(基于 Redis 6.0,略去了结构体细节)
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
    // 调用 epoll_wait 获取就绪事件
    int numevents = epoll_wait(epfd, events, maxevents, timeout);
    for (int i = 0; i < numevents; i++) {
        int fd = events[i].data.fd;
        int mask = 0;
        if (events[i].events & EPOLLIN)  mask |= AE_READABLE;
        if (events[i].events & EPOLLOUT) mask |= AE_WRITABLE;
        // 记录就绪事件,后续主循环会调用相应的处理器
        eventLoop->fired[i].fd = fd;
        eventLoop->fired[i].mask = mask;
    }
    return numevents;
}

五、第四级火箭:高效数据结构

Redis的高性能还离不开精心设计的底层数据结构:

 
外部数据结构底层实现时间复杂度优势
String SDS(简单动态字符串) O(1) 长度获取 杜绝缓冲区溢出,二进制安全
List quicklist(双向链表 + ziplist) 头尾操作 O(1) 内存紧凑,支持快速两端插入
Hash dict(哈希表) + ziplist 平均 O(1) 渐进式rehash,避免瞬时卡顿
Set dict 或 intset O(1) 整数集合自动升级,节省内存
Sorted Set zskiplist(跳表) + dict O(log N) 跳表实现范围查询,媲美平衡树

以 跳表 为例,它在最坏情况下仍能保持 O(log N) 的查找复杂度,且实现比红黑树简单得多。

diagram-flowchart-1

 

六、总结:Redis的“快”是系统性设计的结果

 
设计维度关键技术带来的收益
数据存储 纯内存 消除磁盘I/O,读写速度极快
并发模型 单线程 + IO多路复用 避免上下文切换、锁竞争,简单可靠
事件驱动 epoll 单线程管理10w+连接,非阻塞
数据结构 定制化高效实现(SDS、跳表等) 降低时间与空间复杂度

 

一句话总结:Redis并非“天生就快”,而是通过“内存 + 单线程 + epoll + 高效数据结构”的组合,在速度、复杂度、资源消耗之间找到了最优解。

如果觉得本文对你有帮助,欢迎点赞、收藏、转发
关注我,更多Redis、数据库内核深度内容持续输出。

posted on 2026-06-10 19:39  k8s-Mango  阅读(0)  评论(0)    收藏  举报

导航