Redis IO 多路复用原理与引入原因深度解析

一、引言

1.1 运行程序的性能瓶颈的判断思路是什么?

在讲解 Redis IO 多路复用之前,小编先问大家一个题外话题,就是你会怎么判断一个应用程序哪方面会拖后腿?可以从哪些方面来分析?

首先,从一个软件运行开始,就意味着操作系统需要分配相关资源给它。一个运行的应用程序有三个方面的核心资源。CPU,内存,IO。为什么会是这三个方面。

|-------|------------------------------------------------------------------------------------------------------------------------------------------|
| CPU资源 | 代表着计算能力,是程序执行的核心动力。CPU负责执行指令、完成算法计算以及各种逻辑运算。无论是简单的条件判断,还是复杂的数据处理,本质上都是CPU在进行指令级别的执行。CPU性能的高低,直接决定了单位时间内程序能够处理多少任务。 |
| 内存资源 | 代表着数据的存储与访问能力,是CPU工作的"数据载体"。程序运行过程中所需的变量、对象、中间结果以及缓存数据,都会存放在内存中。CPU无法直接高效地从磁盘获取数据,必须依赖内存作为中转。 |
| IO资源 | 代表着数据的输入与输出能力,是程序与外部世界交互的通道。包括磁盘读写、网络通信、设备交互等。IO操作通常是整个系统中最慢的部分,因为它涉及硬件设备或网络传输。程序需要从磁盘加载数据、通过网络获取请求或返回结果,这些都属于IO范畴。IO性能直接影响系统的响应速度和吞吐能力。 |

【总结】👉一句话:程序运行 = 计算(CPU) + 数据(内存) + 数据流动(IO)

所以:

任何性能瓶颈,本质上不是算得慢,就是拿数据慢,或者搬数据慢

我们可以看一下速度之间的对比

CPU 访问 1 秒

|-----------|------|
| 组件 | 等价时间 |
| L1 Cache | 3 秒 |
| 内存 | 5 分钟 |
| SSD(固态硬盘) | 3 天 |
| HDD(机械硬盘) | 几个月 |

【总结】👉 CPU ≫ 内存 ≫ IO(磁盘 / 网络)

【总结】👉 软件系统:瓶颈 = 磁盘 IO

1.2 Redis 明明把内存当数据库使用,为什么还要优化IO?

Redis 直接把 内存 当作数据库,除去了本地磁盘IO慢的问题。(先不考虑持久化落盘。为什么因为触发次数少,只要不是不合理的触发,几乎不会有太大的影响)为什么还要优化IO

【总结】👉 Redis软件系统:瓶颈 = 内存 + CPU + 网络 IO

我先把问题提出来最后在分析 IO 为什么还要优化,先把 CPU,内存这两个核心资源给分析完,在分析IO的问题。

【问题一】Redis 对 CPU 的性能依赖大吗?CPU 会不会成为瓶颈?

从设计上看,Redis 对 CPU 的依赖并不是其主要瓶颈来源,但在特定场景下仍然可能受到 CPU 限制。

首先,Redis 采用单线程模型执行命令,这带来两个显著特点:

一是避免了多线程上下文切换带来的额外开销;二是天然具备命令执行的原子性。因此,Redis 不需要为线程切换频繁、锁竞争等问题消耗 CPU 资源,这一点相比多线程系统是明显优势。

其次,从计算角度来看,Redis 的大部分操作属于轻量级计算,例如键查找(哈希表)、简单的数据结构操作等,单次命令的 CPU 消耗较低。但在以下场景中,CPU 仍可能成为瓶颈:

  • 大 Key 或高复杂度操作(如 O(n) 命令)
  • Lua 脚本执行
  • 数据结构转换或编码压缩
  • 持久化过程中的计算(如 RDB 压缩、AOF 重写)
  • 内存碎片整理(active defrag)

不过需要注意的是,这些操作大多是阶段性或后台触发的,并非主路径高频操作。因此总体来说,Redis 的 CPU 压力通常可控,但在高复杂度命令或大数据量场景下仍需关注。

总结:Redis 通过单线程模型减少了 CPU 在调度上的浪费,但在复杂命令或数据规模较大时,CPU 仍可能成为性能瓶颈。
【问题二】Redis 对内存的性能依赖大吗?内存会不会成为瓶颈?

内存是 Redis 最核心的资源之一,可以说 Redis 的性能高度依赖内存。

Redis 将内存作为主存储介质,而不是磁盘,这使得数据访问延迟从毫秒级降低到纳秒级,是其高性能的根本原因之一。但这也意味着:

  • 内存容量直接决定数据规模上限
  • 内存访问效率直接影响整体性能
  • 内存管理策略(碎片、分配、淘汰)至关重要

从性能角度看,内存"通常不会拖后腿",原因在于其访问速度远高于 IO。但在以下情况下,内存反而会成为瓶颈:

  • 内存不足,触发淘汰策略(LRU/LFU)
  • 内存碎片严重,导致有效利用率下降
  • BigKey 导致操作阻塞
  • fork(用于 RDB/AOF)时内存页表复制开销大

此外,Redis 的数据安全依赖持久化机制(RDB/AOF),但持久化并不改变其"以内存为主"的本质。

总结:内存是 Redis 的性能基础,正常情况下不会成为短板,但在容量、碎片和数据结构不合理时,会直接影响系统稳定性与性能。
【问题三】Redis 对网络 IO 的性能依赖大吗?网络 IO 会不会成为瓶颈?

在 Redis 架构中,网络 IO 往往是最容易成为瓶颈的部分之一。

Redis 作为一个内存数据库,本质是一个高性能的网络服务,其 IO 主要体现在:

  • 客户端与服务端之间的连接建立与维护
  • 请求命令的发送与解析
  • 响应数据的返回

随着系统并发量的提升,问题会逐渐显现:

第一,大量客户端连接会带来高并发 socket 管理压力。例如上万连接同时存在,如果采用传统阻塞或轮询方式,会导致 CPU 大量浪费在"无效等待"上。

第二,请求量越大,网络传输(带宽 + RTT)就越容易成为限制因素。即使 Redis 内部处理很快,网络也可能成为瓶颈。

第三,数据规模增大后,持久化(RDB/AOF)带来的磁盘 IO 也会间接影响整体性能,尤其是在高写入场景下。

为了解决这些问题,Redis 采用了 IO 多路复用(如 epoll)机制,使单线程可以同时监听大量连接,只处理"就绪事件",避免空轮询,从而大幅提升 CPU 利用率。

总结:Redis 的高性能建立在"内存 + 单线程"的基础上,但真正限制吞吐能力的,往往是网络 IO 和连接管理能力。因此在高并发场景下,网络 IO 更容易成为系统瓶颈。

所以,Redis 在高并发系统设计中,如何高效处理大量客户端连接,是服务端架构的核心问题之一。作为一个以内存操作著称的高性能数据库,Redis 能够轻松支撑数万甚至数十万并发连接,其背后的关键技术之一,就是 IO 多路复用(I/O Multiplexing)

很多人存在一个误区:认为 Redis 6 才引入 IO 多路复用。实际上,Redis 从早期版本就已经使用 IO 多路复用机制 ,Redis 6 的优化是在此基础上引入了 多线程 IO

本文将从问题出发,深入分析 Redis 为什么需要 IO 多路复用,以及它是如何工作的。

二、没有 IO 多路复用会发生什么?

在传统网络编程模型中,方式如下:

一是 阻塞 IO(BIO)------ 一连接一线程。每个客户端连接对应一个线程维持连接着。问题也是随之明显的。

问题一:线程数量随连接数量线性增长。

问题二:内存占用高(线程栈空间,毕竟线程越来越多)。

问题三:CPU 切换线程时上下文开销巨大(socket之间不断轮询,导致线程之间也不断切换)

问题四:难以支撑高并发(1万连接 ≈ 1万个线程)

二是 轮询模型。单线程不断遍历所有连接。问题也是随之明显。

问题一:大量"无效检查"(很多连接没有数据)

问题二:CPU 空转严重 (很多线程没有命令执行,切换到这条线程也没有命令执行)

问题三:时间复杂度 O(n),低效浪费 CPU 资源

重点: Redis 从诞生开始就使用 IO 多路复用 ,并没有经历"先轮询、再升级"的阶段。 上面的图仅仅只是为了方便理解。

❌ Redis 从来没有用"简单轮询"来处理连接

✅ Redis 一开始就是基于 IO 多路复用(select/poll/epoll)设计的

三、什么是 IO 多路复用?

在高并发服务器设计中,一个核心问题是:如何用更少的资源处理更多的客户端连接? 传统模型往往在连接数增加时迅速崩溃,而 IO 多路复用技术的出现,使得单线程也能高效处理成千上万的连接。

同样的成千上万的客户端连接,可能真正有数据只有几百个,传统方案 阻塞IO + 轮询。造成大量无效扫描,线程数量爆炸,上下文切换频繁,CPU空转严重等等。

而 IO 多路复用解决的是:如何无效等待?核心思想就是**让操作系统帮我们监听所有连接,只返回"有事件"的连接。**也就是说将socket 连接数量都"委托"给操作系统来管理。Redis 不管理维护 Socket 连接,这样一来就没有这方面的压力了。

那么问题来了,那是怎么个委托法(IO 多路复用)?才能让 Redis 并没有体会有压力,毕竟就算是委托给操作系统,难道操作系统就不用判断处理哪条客户端连接有命令需要处理?还有就是又是怎么避免大量无效扫描,CPU 空转严重等问题。

带着问题我们一步一步去学习与探索

四,IO 多路复用的三种方式

在传统阻塞I/O模型中,每个连接需要独立分配一个线程或进程来处理。当连接数达到千级甚至万级时,系统资源(线程栈、内存、上下文切换开销)会迅速成为瓶颈。

例如,一个线程默认栈空间约8MB(虚拟内存),1万连接就需要消耗约80GB内存。这个是按照最悲观的态度来计算的。实际上线程刚被创建的时候,仅仅只有几KB,后面随着调度使用会慢慢增长,最大内存空间到8MB。实际物理内存占用 << 8MB。真实情况一个线程可能就是 100KB ~ 500KB。

cs 复制代码
那么
100KB × 10000 ≈ 1GB
500KB × 10000 ≈ 5GB
真实内存
1GB ~ 5GB(而不是 80GB)

尽管是 1~ 5GB,可能有钱人觉得不就是5个G的内存,我有钱,内存就一个字,给我扩充 就完了。但问题依旧存在。首当其冲 的就是上下文切换才是最致命的

cs 复制代码
# 1万线程 → CPU 疯狂切换
# 成本:
#  保存/恢复寄存器
#  cache 失效
#  调度开销

第二个问题 就是调度压力,Linux 调度器需要管理 1万个 runnable 线程,时间复杂度上升。

第三个问题 就是文件描述符 & 内核资源开销也不小,每个连接一个 socket其内核结构体开销也不小。

所以即便如此,1 万个线程仍可能消耗数 GB 内存。同时,更严重的问题在于频繁的线程上下文切换和调度开销,这会显著降低系统性能。

线程栈 8MB 是"上限",不是"实际占用";真正拖垮系统的是线程数量带来的调度和切换成本。

因此,"一连接一线程"模型在高并发场景下难以扩展,这正是 IO 多路复用技术出现的根本原因。

IO 多路复用通过单一线程监控多个文件描述符,实现了"一个线程处理万级连接"的能力。三种机制的演进时间线如下:

  • select(1983年):BSD系统首次引入,通过位图管理fd集合
  • poll(1997年):System V系统改进,使用动态数组替代固定位图
  • epoll(2002年):Linux 2.5.44内核引入,基于事件驱动的回调机制

select:最古老的多路复用机制

select是最早出现的IO多路复用机制。其核心函数原型如下:

复制代码
int select(int nfds, fd_set *readfds, fd_set *writefds, 
           fd_set *exceptfds, struct timeval *timeout);

select使用三个位掩码(fd_set类型)来分别表示读、写、异常的文件描述符集合。fd_set本质上是一个位图(bitset) ------使用位图中对应的位来表示要监视的文件描述符。

cs 复制代码
# select的工作流程如下:
#     1. 用户将需要监控的fd集合(位图)传入内核
#     2. 内核遍历所有fd,检查其状态
#     3. 当有fd就绪或超时时,select返回
#     4. 内核修改位图------只保留就绪的fd,未就绪的被清除
#     5. 用户需要再次遍历整个位图,找出哪些fd真正就绪了
# 需要注意的是,readfds、writefds和exceptfds都是输入输出型参数:
# 输入时告诉内核要关心哪些fd,
# 输出时内核告诉用户哪些fd已经就绪。

简单的理解就是,redis 将需要维护的客户端的Socket连接线程都委托给 select 多路复用的方式维护。select 会将超时,未就绪状态的线程都给移除掉,剩下的都是状态正常或者有数据的线程。但是我们可以感觉到,确实和轮询相比排除一些超时或未就绪状态的线程。减少一部分工作量但不多。

并且 select 也有很严重的缺陷限制。

问题一--O(n)线性扫描:每次调用select,内核都需要遍历所有被监控的fd来检查状态,时间复杂度为O(n)。当连接数达到10万时,单次select调用耗时可达毫秒级

**问题二--大量内存拷贝:**每次调用select都需要将fd_set从用户态的空间拷贝到内核态的空间,返回时再从内核态拷贝回用户态的空间。高并发场景下,这种拷贝消耗的资源是惊人的。

问题三--文件描述符数量限制 :select使用fd_set位图管理fd,默认最多支持1024个文件描述符(由FD_SETSIZE宏定义限制)。虽然可以通过修改宏重新编译内核来提升,但治标不治本。

cs 复制代码
# 适用场景
#     连接数较少(<1000)的轻量级应用
#     需要兼容多种Unix-like系统的跨平台场景
#     实时性要求极高的场景(select的timeout精度为微秒,而poll和epoll为毫秒)
#     简单应用或学习目的

还不如不用,现在的电脑1000 的连接量还是随便接得住的。毕竟这个是1983年时代的产物。

poll: 突破数量限制的改进版

poll是对select的改进,其核心函数原型如下:

复制代码
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd {
    int fd;         // 文件描述符
    short events;   // 监控的事件(输入)
    short revents;  // 返回的事件(输出)
};

poll使用一个pollfd结构体数组来代替select的位图,每个结构体包含文件描述符和对应的事件掩码。这种方式突破了select的1024个fd数量限制,理论上只受系统内存和文件描述符上限的约束。

缺陷所在,尽管poll解决了fd数量限制,但其本质问题依然存在

(1)O(n)线性扫描 :poll仍然需要遍历整个pollfd数组来检查每个fd的状态,时间复杂度仍为O(n)。10万连接时,单次poll调用仍需约1.8ms。

(2)大量内存拷贝 :每次调用poll都需要将整个pollfd数组从用户空间拷贝到内核空间。无论fd是否就绪,全部都要拷贝一遍。

(3)重复初始化 :每次调用poll都需要重新设置events字段。

(4)内存开销pollfd数组占用连续内存,大连接数时容易产生内存碎片

复制代码
适用场景
    连接数在1K-10K之间的中等规模应用
    需要同时监控读写事件的场景
    平台支持poll且对实时性要求不高的场景
    对内存占用不敏感的环境

对实时性响应要求不高的可以接受使用 poll。但redis 肯定不适用。

epoll:革命性的事件驱动机制

epoll是Linux特有的I/O多路复用机制,它从根本上一举解决了select和poll的性能瓶颈。epoll的核心设计包含三个关键组件:

(1)红黑树(Red-Black Tree) :内核使用红黑树高效管理所有被监控的fd,增删改操作的时间复杂度为O(log n)。用户通过epoll_ctl增删fd,无需像select/poll那样每次传入整个集合。

(2)就绪列表(Ready List) :内核维护一个双向链表,只存储已经就绪的活跃fd。

(3)回调机制:当fd状态发生变化时,内核通过回调函数自动将其加入就绪列表。

复制代码
【epoll 的本质】epoll = 事件驱动 + 内核维护就绪队列 + 用户只处理活跃连接  

epoll 为什么比 select / poll 快?

|-------------|--------------|
| 模型 | 工作方式 |
| select/poll | 每次遍历所有 fd |
| epoll | 只返回"有事件的 fd" |

❗ epoll 把"遍历"这件事,从"每次循环做"变成了"只有事件发生时做"

Redis 在 Linux 上采用的就是 epoll 的方式。这样的话,就相当于操作系统的 epoll 多路复用是 Redis 的"叫号系统",只有"被叫到号"(事件监听被触发)Redis 才会处理。这样 Redis 就只会处理有数据的线程。因为有数据才会触发事件监听,事件监听触发之后就会被 redis 接收到。之后就交给主线程执行命令即可。

标准的epoll 流程

复制代码
        ┌──────────────┐
        │  客户端连接   │
        └──────┬───────┘
               ↓
        socket fd 创建
               ↓
        epoll_ctl 注册事件
               ↓
        ┌──────────────────┐
        │   事件循环(ae)  │
        │   epoll_wait     │
        └──────┬───────────┘
               ↓
        有事件返回 fd
               ↓
        调用对应 handler
               ↓
   ┌───────────────┬──────────────┐
   ↓               ↓              ↓
读事件         写事件        定时事件
处理命令       返回结果       过期key等

Redis 在 Linux 上基于 epoll 实现 I/O 多路复用,通过单线程事件驱动模型,实现了对万级连接的高效处理,是其高性能的核心基础之一。

五,Redis 的 AE模块

AE 模块,全称 Abstract Event(事件抽象层),它本质是 Redis 自己实现的一套

复制代码
# 跨平台 I/O 多路复用封装 + 事件驱动框架
# 也就是说 AE = Redis 的"事件引擎" 基于不同的操作系统采用不同的多路复用方案

比如:

|-------|---------|
| 系统 | 使用 |
| Linux | epoll ✅ |
| macOS | kqueue |
| 老系统 | select |

AE 模块的设计精髓(非常重要🔥)

1. 抽象层设计(跨平台)

Redis 没直接写 epoll:👉 而是:

复制代码
aeApiPoll()
aeApiAddEvent()

不同系统实现不同版本

👉 这就是:

💡 "面向接口编程"在 C 语言的体现


2. Reactor 模式(核心思想)

Redis AE 本质就是:

👉 Reactor 模式

流程:

复制代码
事件注册 → 事件监听 → 事件分发 → 事件处理

3. 单线程 + 多路复用

👉 Redis 没有:

  • 线程池
  • 多线程 IO

而是:

👉 一个线程 + epoll 管理万级连接

Redis 6 之后引入多线程 + epoll 管理万级连接

👉 Redis AE ≠ epoll

👉 Redis AE = epoll + 事件调度 + 时间事件 + 抽象层

一张结构图帮你彻底理解

cs 复制代码
            ┌──────────────┐
            │   Redis AE   │
            │ (事件框架    │
            └──────┬───────┘
                   │
     ┌─────────────┼─────────────┐
     │             │             │
┌────▼────┐  ┌─────▼────┐  ┌─────▼────┐
│ epoll   │  │ kqueue   │  │ select   │
│ Linux   │  │ macOS    │  │ fallback │
└─────────┘  └──────────┘  └──────────┘

六、延伸思考(面试加分点)

(1)Redis 是使用单线程还是多线程,如果不是单线程,那为什么不用多线程执行命令?

首先需要明确:在 Redis 6.0 之前,Redis 是完全单线程的;但从 Redis 6.0 开始,Redis 引入了多线程,不过仅仅是用于"网络 I/O 和协议解析",核心的"命令执行"依然是单线程的。

为什么核心的命令执行要坚持单线程?主要有以下几个原因:

  1. CPU 不是瓶颈,内存和网络才是:Redis 是基于纯内存的操作,内存的读写速度极快(纳秒级)。在大多数场景下,CPU 处理命令的速度远快于网络传输和内存访问的速度。多线程并不能突破内存带宽和网络带宽的物理极限。
  2. 避免上下文切换开销:Redis 的命令执行时间通常在微秒甚至亚微秒级别。如果使用多线程,线程上下文切换的开销可能会比命令执行本身的时间还要长,得不偿失。
  3. 避免锁竞争和死锁:多线程共享内存数据必然需要加锁。锁的竞争、死锁的排查会极大降低性能,并让代码变得极其复杂。单线程天然避免了这些问题。
  4. 保证原子性:单线程串行执行命令,天然保证了每个命令执行的原子性,不需要像关系型数据库那样引入复杂的 MVCC(多版本并发控制)或锁机制。
  5. 简化设计与维护:单线程模型让 Redis 的代码非常简洁,易于开发、调试和维护。

补充:Redis 6.0 的多线程做了什么?

Redis 6.0 发现随着网卡带宽的提升(如万兆网卡),单线程处理网络 I/O(接收数据、解析 RESP 协议、发送数据)成为了瓶颈。因此,它引入了多个 I/O 线程来并行处理网络读写和协议解析,但在将解析好的命令交给核心执行引擎时,依然通过全局锁保证单线程串行执行

(2)epoll 和 select/poll 的区别?

这三者都是 I/O 多路复用机制,但 epoll 是 Linux 下对 select/poll 的全面升级,核心区别如下:

|-------------|---------------------------------------------------------------|----------------------------------------------------------------------|
| 特性 | select / poll | epoll |
| 数据结构 | 基于数组/链表。 | 基于红黑树 (存储监听的 fd)和双向链表(存储就绪的 fd)。 |
| 最大连接数 | select 有硬性限制(通常 1024,由 FD_SETSIZE 决定);poll 无硬性限制,但受限于系统内存。 | 没有硬性上限,上限是系统最大文件描述符数量(通常 10W+,受限于系统内存)。 |
| fd 遍历方式 | 线性遍历 O(N)。每次调用都需要遍历整个 fd 集合,检查哪个 fd 就绪。当连接数多但活跃连接少时,效率极低。 | 回调机制 O(1) 。只有活跃的 fd 才会触发回调,将其加入就绪链表。epoll_wait 只返回就绪的 fd,无需遍历。 |
| 内存拷贝 | 每次调用都需要将整个 fd 集合从用户态拷贝到内核态。 | 监听集合通过 mmap 让内核和用户空间共享内存,避免了全量拷贝(仅就绪 fd 需要拷贝到用户态)。 |
| 触发模式 | 仅支持水平触发(LT)。 | 支持水平触发(LT)边缘触发(ET)。ET 模式下,只有状态发生变化时才通知,效率更高。 |

总结 :在海量连接但活跃连接较少的场景下(如 Web 服务器),epoll 的性能呈线性甚至指数级碾压 select/poll

(3)Redis 事件循环如何实现?

Redis 没有使用 libevent 等第三方事件库,而是自己实现了一个轻量级的事件处理库,叫做 ae (Async Event) 。它基于 Reactor 模式,核心实现逻辑如下:

  1. 核心结构 aeEventLoop: 事件循环的核心是一个结构体,里面主要维护两类事件:
    • 文件事件(File Events):处理网络 I/O(如客户端连接、读写数据)。
    • 时间事件(Time Events) :处理定时任务(如 serverCron,用于定期清理过期键、持久化 RDB/AOF、内存淘汰等)。
  1. 底层 I/O 多路复用封装 : ae 库在底层封装了 epoll、kqueue、evport、select 等 API。在 Linux 环境下,Redis 会优先编译并使用 epoll
  2. 事件循环主函数 aeMain: Redis 启动后,会进入一个无限循环 aeMain,其核心逻辑是调用 aeProcessEvents
    • 第一步:处理文件事件 。调用底层的 epoll_wait 获取就绪的 fd。如果有读事件就绪,调用读事件处理器(如 readQueryFromClient 接收并解析命令);如果有写事件就绪,调用写事件处理器(如 sendReplyToClient 返回结果)。
    • 第二步:处理时间事件 。遍历时间事件链表,检查是否有到期的定时任务。如果有,则执行对应的处理函数(如执行一次 serverCron)。
    • 第三步:计算下一次阻塞时间 。根据最近的一个时间事件,计算 epoll_wait 需要阻塞的超时时间,然后进入下一次循环。

(4)为什么 Redis 性能仍然很高?

即使核心命令执行是单线程,Redis 依然能轻松达到 10万+ QPS,其高性能的秘诀在于"把每一滴性能都榨干":

  1. 纯内存操作:这是最根本的原因。所有数据都在内存中,避免了磁盘 I/O 的机械延迟。内存的响应时间是纳秒级,而磁盘是毫秒级,相差十万倍。
  2. 高效的数据结构:Redis 没有使用通用的数据结构,而是针对各种场景设计了专属结构。例如:
    • 使用 SDS(简单动态字符串)替代 C 语言原生字符串,获取长度 O(1),且杜绝缓冲区溢出。
    • 针对小数据量使用 ziplist、quicklist、intset、hashtable 等紧凑结构,极大节省内存并提高 CPU 缓存命中率。
  1. I/O 多路复用机制 :使用 epoll 机制,单线程可以同时监听和处理数以万计的并发连接,实现了非阻塞的高效网络 I/O。
  2. 单线程避免了开销:如前所述,单线程避免了多线程的上下文切换和锁竞争,让 CPU 100% 专注于执行命令。
  3. 轻量级的事件循环:自己实现的 ae 事件库,去除了第三方库的冗余代码,极其轻量高效。
  4. 底层 C 语言优化:Redis 使用 C 语言编写,贴近硬件,避免了不必要的内存拷贝,并且对内存对齐、CPU 缓存行等底层细节做了大量优化。
  5. 简单的协议与批量操作
    • 使用 RESP 协议,解析极其简单高效。
    • 支持 Pipeline(管道)Lua 脚本,允许客户端批量发送命令或在服务端原子执行一段逻辑,大幅减少了网络 RTT(往返时间)带来的延迟。
相关推荐
鹏易灵2 小时前
C++——8.移动语义初探(移动构造、移动赋值)
开发语言·c++·php
Database_Cool_2 小时前
单库瓶颈解决方案首选:阿里云 PolarDB-X 平滑替代分库分表
数据库·阿里云
2503_931712482 小时前
10m/s超高速电梯:西奥XO-NEWIII如何树立行业速度标杆
java·大数据·数据库
无小道2 小时前
Redis——redis和mysql的数据同步
数据库·redis·mysql
AI的探索之旅3 小时前
从 Ubuntu 14.04 到 24.04:TI AM335x 开发环境完整迁移与 Agent 接管方案
linux·数据库·嵌入式硬件·ubuntu·postgresql
宠友信息3 小时前
资源权限与钱包流水在即时通讯源码后端架构中的设计
java·spring boot·redis·websocket·缓存
辰合软件3 小时前
通达OA目录结构与核心文件解析
android·数据库·oracle
_Jimmy_3 小时前
Redis.from_url()连接redis时,redis密码带有#号报错
redis
名不经传的养虾人3 小时前
从0到1:企业级AI项目迭代日记 Vol.61|记忆不是越多越好,装一道门比装满更重要
数据库·人工智能·ai编程·ai工作流·企业ai