io_uring
了解io_uring,可以看看如下link文章:
https://blog.csdn.net/LAN_chen_ning/article/details/159965083
https://cloud.tencent.com/developer/article/2651888
Reactor 与 Proactor 模式 通俗完整讲解
一、先一句话本质区别
- Reactor:事件通知 + 自己做 IO内核告诉你:有数据来了 / 可写了,然后你自己调用 read/recv 去读。
- Proactor:IO 完成通知 + 内核帮你做完 IO你提前把读 / 写任务交给内核,内核做完读写后,只通知你:已经读完了,数据给你放好了。
二、Reactor 模式(同步事件驱动)
1. 工作流程
- 应用注册fd 读 / 写事件到多路复用器(epoll/kqueue/select)
- 内核等待事件就绪
- 事件到达 → 内核唤醒应用
- 应用自己调用 recv/read/send/write完成实际 IO
- 处理业务逻辑
2. 形象理解
你去食堂排队,服务员喊你:“你的饭好了”你自己上去端饭回来吃。
3. 特点
- IO 事件由内核监听
- 实际读写由用户态代码执行
- 属于同步非阻塞模型
4. 典型开源库
- muduo
- libevent
- libev
- libuv
- Nginx
- 大部分 Linux 网络框架
5. 优点
- 逻辑简单、好理解、好调试
- Linux 下生态成熟、性能足够高
- 开发门槛低
6. 缺点
- 事件触发后还要再调用一次系统调用去读写
- 高并发下系统调用开销累积
三、Proactor 模式(异步事件驱动)
1. 工作流程
- 应用提前发起异步读 / 写请求,把缓冲区交给内核
- 内核自己负责等待数据、拷贝到用户缓冲区
- IO 真正完成后,内核给应用发完成事件
- 应用直接处理已经读到好的数据,不用再调用 recv
2. 形象理解
你点餐留地址,食堂做好直接送餐到你桌上你不用自己去端,直接开吃。
3. 特点
- 内核全权包办 IO 读写
- 用户态只接收「IO 完成」通知
- 真正异步 IO模型
4. 典型开源 / 系统
- WindowsIOCP标准 Proactor
- Boost.Asio(跨平台封装成 Proactor 风格)
- Java NIO2 AIO
- 部分基于 io_uring 封装的框架
5. 优点
- 少系统调用,内核批量处理 IO
- 用户态不用循环读写,CPU 开销更低
- 高并发极限吞吐更强
6. 缺点
- 逻辑比 Reactor 复杂很多
- 编程模型反直觉,回调 / 异步链难写
- Linux 原生 AIO 弱,靠 io_uring 才像样
四、核心对比表
| 维度 | Reactor | Proactor |
|---|---|---|
| IO 谁做 | 用户态自己 read/recv | 内核自动完成读写 |
| 触发通知 | 通知「可读 / 可写」 | 通知「已读完 / 已写完」 |
| 模型类型 | 同步非阻塞 | 真正异步 |
| 系统调用次数 | 多(事件 + 再读写) | 少(只提交一次任务) |
| 编程难度 | 简单、直观 | 复杂、反直觉 |
| 代表框架 | muduo、libevent、libuv | IOCP、Boost.Asio、io_uring 高级封装 |
| 平台偏好 | Linux 标配 | Windows 原生支持,Linux 靠 io_uring |
五、和你之前学的技术对应
- epoll→ 天然适配Reactor
- io_uring→ 可以轻松实现Proactor语义(内核替你做 accept/recv/send)
- muduo/libuv都是标准Reactor 实现
- Boost.Asio对外统一封装成Proactor 编程风格,底层 Linux 用 epoll 模拟、Windows 用 IOCP 原生
六、最简单记忆口诀
- Reactor:有事喊你,自己去读
- Proactor:帮你做完,直接给结果
Direct I/O 与 Buffered I/O 通俗易懂详解(Linux 标准)
一、先搞懂核心区别
1. Buffered I/O 缓冲 I/O(默认普通读写)
也叫Cache I/O,Linux 所有read/write、fread/fwrite默认都是 Buffered I/O。
2. Direct I/O 直接 I/O
绕过操作系统页缓存(Page Cache),应用程序直接和磁盘硬件读写数据,不经过内核缓存。
二、Buffered I/O 原理流程
写流程
应用缓冲区 →内核 Page Cache(页缓存)→ 内核后台刷盘 → 磁盘硬件
读流程
磁盘硬件 →内核 Page Cache→ 应用缓冲区
核心特点
- 有操作系统页缓存兜底
- 第一次读进缓存,第二次直接从缓存拿,极快
- 写操作先写缓存,不立刻落盘,内核异步延迟刷盘
- 系统自动预读、缓存热点数据
Buffered I/O 优点
- 读写延迟低、命中率高
- 内核帮你做预读、缓存、合并 IO、调度
- 接口简单,不用管对齐、块大小
- 普通文件、日志、配置、业务程序默认首选
Buffered I/O 缺点
- 多了一次用户态 ↔ 内核态数据拷贝
- 占用大量内存做 Page Cache,内存大时会吃满内存
- 掉电可能缓存数据没刷盘,丢失数据
三、Direct I/O 原理流程
读写都直接跨过 Page Cache
应用缓冲区 ⇨直接磁盘硬件
强制约束(必须满足,否则调用失败)
- 内存地址对齐:必须按 4K/512 字节对齐
- 读写长度对齐:必须是磁盘块大小整数倍(常见 512B、4K)
- 文件偏移对齐:读写起始偏移也要对齐
Direct I/O 优点
- 无 Page Cache 内存占用,不抢占系统缓存内存
- 少一次数据拷贝:用户态直接到磁盘,CPU 开销更低
- 不污染系统页缓存,适合数据库自己管理缓存
- 读写实时落盘,可控性强,内核不干预
Direct I/O 缺点
- 无系统缓存、无预读,重复读性能差
- 强制对齐,编程麻烦,自己要管理内存块
- 小 IO 性能极差,只能适合大块顺序读写
- 没有内核 IO 合并,随机小 IO 压力很大
四、关键核心对比表
表格
| 对比项 | Buffered I/O 缓冲 I/O | Direct I/O 直接 I/O |
|---|---|---|
| 是否走 Page Cache | ✅ 是 | ❌ 绕过 |
| 数据拷贝 | 多一次内核拷贝 | 零拷贝,直达磁盘 |
| 缓存策略 | 内核自动管理 | 应用自己管理缓存 |
| 读写对齐要求 | 无要求 | 必须内存 / 偏移 / 长度对齐 |
| 重复读取速度 | 极快(命中缓存) | 慢(每次都读磁盘) |
| 内存占用 | 占用系统 Page Cache | 不占 Page Cache |
| 适用场景 | 普通文件、日志、配置、Web 服务 | 数据库、存储引擎、大数据 |
| 编程难度 | 简单 | 复杂 |
五、各自典型使用场景
什么时候用 Buffered I/O(默认)
- 普通业务程序读写配置、日志
- Web 服务、Nginx、业务小文件
- 偶尔读取、热点不多的文件
- 不想处理对齐、只想简单读写
什么时候必须用 Direct I/O
数据库 / 存储引擎专用
- MySQL、PostgreSQL、Redis RDB
- LevelDB、RocksDB、TiDB
- 分布式存储、块存储、大数据读写
原因:数据库自己有自己的内存缓存池,不需要内核 Page Cache;用 Direct I/O 绕过系统缓存,避免双重缓存浪费内存,还能自主控制刷盘时机。
六、Linux 如何开启
Buffered I/O
默认open()不加任何特殊标志就是:
c
运行
fd = open("a.txt", O_RDWR);Direct I/O
加O_DIRECT标志:
c
运行
fd = open("data.dat", O_RDWR | O_DIRECT);七、一句话极简总结
- Buffered I/O:过内核缓存,省心、快、适合普通业务,掉电可能丢数据。
- Direct I/O:绕内核缓存,无内存浪费、少拷贝,数据库 / 存储专用,编程要处理对齐。
