找回密码
 立即注册
首页 业界区 业界 redis为什么这么快?I/O多路复用技术是什么? ...

redis为什么这么快?I/O多路复用技术是什么?

卜笑 2 小时前
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)边缘触发只有状态发生变化(数据从无到有)时才通知一次。极其高效,但要求开发者必须一次性读完所有数据,否则剩下的数据可能永远不会被处理。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册