redis的I/O多路复用技术原理解析

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: Redis高性能源于内存存储、单线程模型、I/O多路复用及优化数据结构。其核心通过epoll实现非阻塞多路复用,以事件驱动高效处理高并发连接,结合SDS、跳表等结构,极致提升响应速度与资源利用率。

redis能够达到每秒10万+ QPS(每秒查询率)的极高性能,并非只因为它是“内存数据库”,而是由存储介质、线程模型、网络模型以及数据结构优化共同决定的。
以下是redis快的具体原因:
绝大部分请求在内存中完成

这是 Redis 快的根本原因。相比于传统数据库(如 MySQL)需要从磁盘读取数据,Redis 直接操作RAM(内存)。

存储介质 访问速度(数量级) 延迟说明
内存 (RAM) 纳秒 (ns) 极快,就像从书桌上拿书。
固态硬盘 (SSD) 微秒 (μs) 较快,但比内存慢 1000 倍。
机械硬盘 (HDD) 毫秒 (ms) 慢,就像去图书馆借书。

Redis 避免了磁盘 I/O 产生的巨大开销,数据操作几乎是瞬时的。
纯粹的单线程模型

很多人误以为多线程才快,但 Redis 的核心处理逻辑是单线程的(主要指文件事件分路器处理请求的部分)。

没有上下文切换:多线程在切换执行流时需要保存和加载 CPU 寄存器状态,这会产生明显的性能损耗。
没有锁的竞争:在多线程环境下,为了保证数据安全,必须引入锁(如互斥锁)。Redis 单线程执行,天然避免了死锁和锁竞争带来的开销。
简单即高效:单线程代码逻辑更简单,也更容易维护。
注意: Redis6.0引入了多线程来处理网络I/O,但执行命令的核心逻辑依然是单线程的。

非阻塞I/O多路复用 (I/O Multiplexing)

Redis 使用了I/O多路复用技术(如 Linux 下的 epoll)来处理大量的并发连接。

原理:Redis并不是为一个连接分配一个线程,而是让一个线程监控数千个连接的状态。只有当某个连接真正有数据发过来时,Redis才会去处理。
效果:即使有成千上万个客户端同时连接,Redis 也能像一个老练的服务员同时照顾几十桌客人一样,谁叫就服务谁,而不需要在桌子之间来回空跑。

针对性优化的底层数据结构

Redis的开发者对每种数据类型都进行了极致的底层优化,并没有简单地使用编程语言内置的结构。

SDS (简单动态字符串):相比 C 语言原生字符串,获取长度的时间复杂度从O(N)降到了O(1),且减少了内存分配次数。
跳表 (SkipList):为有序集合 (ZSet) 提供平衡树一般的查找效率,但实现更简单,支持范围查询更高效。
压缩列表 (ZipList) / 整型数组: 在数据量较小时使用紧凑存储,极大节省了内存开销,提高了 CPU 缓存命中率。

总结:

Redis的快可以总结为:基于内存操作 + 单线程 + 多路复用的并发 + 极致优化的底层数据结构。
详细说一下I/O多路复用
I/O多路复用(I/O Multiplexing)是现代高性能网络服务器(如 Nginx, Redis, Node.js)的核心基石。简单来说,它是一种 让单个线程能够同时监控多个网络连接(文件描述符) 的技术。

I/O多路复用解决了“高并发下的线程开销问题”。
在没有这项技术前,我们要支撑 1 万个并发连接,可能需要启动1万个线程,这会导致内存耗尽和CPU频繁的上下文切换。
有了 I/O 多路复用(尤其是 epoll),我们可以用一个线程轻松管理成千上万个连接,极大提升了系统的吞吐量。

举例理解:

假设一家餐厅有 100 桌客人:

阻塞 I/O (Blocking I/O): 一个服务员盯一桌客人。客人不点菜,服务员就死等。要服务 100 桌,就得请 100 个服务员。(开销巨大,线程切换成本高)
非阻塞 I/O (Non-blocking I/O): 一个服务员在 100 桌之间不停轮询:“点菜吗?”“不点。”“点菜吗?”“不点。” (效率低下,CPU 全在跑无意义的询问)
I/O 多路复用: 服务员在前台放一个呼叫器。哪桌客人想点菜了,就按一下呼叫器,呼叫器亮起对应的桌号。服务员只需要盯着这个呼叫器,哪桌亮了去哪桌。 (这就是 I/O 多路复用)

三种核心实现机制

在Linux中,I/O 多路复用经历了从select 到 poll 再到 epoll的演进。
select:select 是最早的实现。它维护一个存放文件描述符(FD)的集合。

工作方式:每次调用都要把整个集合从用户态拷贝到内核态,内核线性扫描所有 FD。
缺点:有1024的数量限制(硬编码)。由于是线性扫描,时间复杂度为 O(n),连接越多越慢。

poll:基本解决了数量限制问题。

工作方式:使用链表存储 FD。
缺点:依然需要遍历整个集合来找出哪个 FD 就绪,性能随连接数增加而线性下降。

epoll (Linux的终极武器)

epoll是目前Linux下处理百万级别并发的首选。它不再像select那样盲目扫描,而是采用事件通知机制。

深入解析epoll的原理

epoll的高效源于它在内核中维护了两个核心数据结构:
    红黑树 (RB-Tree):用于存储所有待监控的 FD。查找、插入、删除的时间复杂度都是O(log n)。
    就绪列表 (Ready List):这是一个双向链表。当某个FD有事件发生时,内核会通过回调机制将其放入这个列表中。
epoll的工作流程:
    epoll_create:在内核开辟一块空间,建立红黑树和就绪列表。
    epoll_ctl:向红黑树中添加或删除需要监控的连接。
    epoll_wait:线程只需检查就绪列表。如果列表为空,线程睡眠;如果有数据,直接处理列表里的FD。
    结论:无论你有100个还是100万个连接,epoll只关注活跃的连接,时间复杂度近似O(1)。

两种触发模式:LTvsET

在使用epoll时,有两个非常重要的触发模式,这直接影响代码逻辑:

模式 名称 表现
LT(Level Triggered) 水平触发(默认) 只要缓冲区里还有数据没读完,内核就会不断通知你。比较安全,不容易漏掉数据。
ET(Edge Triggered) 边缘触发 只有状态发生变化(数据从无到有)时才通知一次。极其高效,但要求开发者必须一次性读完所有数据,否则剩下的数据可能永远不会被处理。

相关文章
|
2月前
|
开发框架 弹性计算 运维
建站系统哪个好?2025年建站系统深度推荐与避坑指南
建站系统分传统CMS(如PageAdmin)、SaaS平台(如阿里云速成美站)和开发框架三类。选择时需权衡控制权、成本与效率,根据业务需求、技术能力和长期规划理性选型,优先验证可行性再迭代升级。
360 0
|
存储 NoSQL 安全
Redis的两种持久化方式---RDB、AOF
通过本文的介绍,我们详细讲解了Redis的两种主要持久化方式:RDB和AOF。每种方式都有其独特的优缺点和适用场景。在实际应用中,可以根据具体需求选择合适的持久化方式,或者同时启用RDB和AOF,以达到最佳效果。希望本文能帮助您更好地理解和应用Redis的持久化机制,构建高效、可靠的数据存储解决方案。
1213 79
|
消息中间件 监控 Java
RocketMQ 同步发送、异步发送和单向发送,如何选择?
本文详细分析了 RocketMQ 中同步发送、异步发送和单向发送三种消息发送方式的原理、优缺点及适用场景。同步发送可靠性高但延迟较大,适合订单系统等场景;异步发送非阻塞且延迟低,适用于实时数据处理等场景;单向发送高效但可靠性低,适用于日志收集等场景。文章还提供了示例代码和核心源码分析,帮助读者更好地理解每种发送方式的特点。
2463 4
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
2356 15
|
缓存 关系型数据库 MySQL
一文彻底弄懂MySQL优化之深度分页
【10月更文挑战第24天】本文深入探讨了 MySQL 深度分页的原理、常见问题及优化策略。首先解释了深度分页的概念及其带来的性能和资源问题。接着介绍了基于偏移量(OFFSET)和限制(LIMIT)以及基于游标的分页方法,并分析了它们的优缺点。最后,提出了多种优化策略,包括合理创建索引、优化查询语句和使用数据缓存,帮助提升分页查询的性能和系统稳定性。
1871 1
|
存储 缓存 负载均衡
图解一致性哈希算法,看这一篇就够了!
近段时间一直在总结分布式系统架构常见的算法。前面我们介绍过布隆过滤器算法。接下来介绍一个非常重要、也非常实用的算法:一致性哈希算法。通过介绍一致性哈希算法的原理并给出了一种实现和实际运用的案例,带大家真正理解一致性哈希算法。
28861 66
图解一致性哈希算法,看这一篇就够了!
|
Prometheus 监控 Cloud Native
高频面题: 你们线上 QPS 多少?你 怎么知道的?
本文由45岁资深架构师尼恩撰写,针对高级开发和架构师面试中的高频问题提供详细解答。文章涵盖了QPS、TPS、RT等性能指标的定义及计算方法,详解了如何配置Prometheus与Grafana监控系统QPS,并提供了应对高并发场景(如双十一抢购)的系统部署策略。此外,还分享了多个大厂面试真题及解决方案,帮助读者在面试中充分展示技术实力,提升求职竞争力。建议收藏并深入学习,为面试做好充分准备。更多内容可参考《尼恩Java面试宝典》及相关技术圣经系列PDF。
|
Java Maven Spring
springboot学习一:idea社区版本创建springboot项目的三种方式(第三种为主)
这篇文章介绍了在IntelliJ IDEA社区版中创建Spring Boot项目的三种方法,特别强调了第三种方法的详细步骤。
14748 0
springboot学习一:idea社区版本创建springboot项目的三种方式(第三种为主)
|
Java 编译器 Spring
面试突击78:@Autowired 和 @Resource 有什么区别?
面试突击78:@Autowired 和 @Resource 有什么区别?
17405 7