跳转到正文
zeno's blog
返回

Rust 异步生态(总览):从 mio 到 axum 的分层架构

Table of contents

Open Table of contents

TL;DR

Rust 的异步网络栈是 mio → tokio → hyper → tower → axum 五层,每层职责单一、可独立替换。C++ Asio 把事件通知、调度、定时器、buffer、协程支持打包在一个库里。两种设计没有绝对优劣——Rust 的分层来自语言特性(ownership 使模块边界天然清晰),Asio 的一体化来自 C++ 生态的碎片化(没有统一运行时,不如自己全做)。


分层架构总览

┌──────────────────────────────────────────────────────────┐
│                        应用代码                           │
├──────────────────────────────────────────────────────────┤
│  axum        │ Web 框架:路由、提取器、响应               │
│              │ 零宏路由、编译期参数解析、IntoResponse      │
├──────────────────────────────────────────────────────────┤
│  tower       │ 中间件:Service trait + Layer 组合          │
│              │ 限流、重试、超时、背压——协议无关            │
├──────────────────────────────────────────────────────────┤
│  tower-http  │ HTTP 专用中间件:Trace、Compression、CORS  │
├──────────────────────────────────────────────────────────┤
│  hyper       │ HTTP 协议:HTTP/1.1 + HTTP/2 编解码        │
│              │ Body trait、连接管理                        │
├──────────────────────────────────────────────────────────┤
│  tokio       │ 异步运行时:work-stealing 调度器            │
│              │ 任务系统、定时器(时间轮)、同步原语         │
├──────────────────────────────────────────────────────────┤
│  mio         │ I/O 事件通知:epoll / kqueue / IOCP 薄封装 │
│              │ Poll + Token + Events,极简 Reactor         │
├──────────────────────────────────────────────────────────┤
│  操作系统     │ epoll / kqueue / IOCP / io_uring           │
└──────────────────────────────────────────────────────────┘

每层职责与边界

crate职责不做什么
I/O 事件通知mio跨平台 fd 就绪通知不做 buffer、timer、async/await、调度
异步运行时tokio任务调度 + I/O 驱动 + timer + 同步原语不做 HTTP 协议、路由、中间件
HTTP 协议hyperHTTP/1.1 + HTTP/2 编解码不做路由、参数提取、中间件组合
中间件抽象towerService trait + Layer 组合不做 HTTP 特定逻辑
HTTP 中间件tower-httpCompression / CORS / Trace 等不做路由
Web 框架axum路由 + 提取器 + 响应不做 HTTP 协议解析、不发明中间件系统

与 C++ Asio 的架构对比

C++ Asio(一个库包含一切)          Rust(分层栈)
┌─────────────────────────┐      ┌──────────────┐
│ io_context              │      │ axum         │ ← Web 框架
│ ├── epoll_reactor       │      ├──────────────┤
│ ├── strand              │      │ tower        │ ← 中间件
│ ├── timer_queue         │      ├──────────────┤
│ ├── tcp::socket         │      │ hyper        │ ← HTTP
│ ├── buffer              │      ├──────────────┤
│ ├── ssl::stream         │      │ tokio        │ ← 运行时
│ ├── resolver            │      ├──────────────┤
│ └── coroutine support   │      │ mio          │ ← I/O 事件
└─────────────────────────┘      └──────────────┘
维度C++ AsioRust 栈
异步模式Proactor(向 IOCP 对齐)Reactor(mio)+ Future/async(tokio)
线程模型用户手动管理(多线程 run())work-stealing 调度器(tokio)
中间件无统一抽象tower Service trait
定时器最小堆分层时间轮(tokio)
内存安全用户负责(shared_from_this 模式)所有权系统 + 借用检查器
并发保护strandSend + Sync trait 静态检查
Buffer非拥有式(指针+长度)所有权明确(Bytes, Vec
协程完成令牌机制统一 5 种风格async/await 是语言内置
标准化Networking TS 未进标准无标准运行时(tokio 是事实标准)

核心设计分歧:为什么 Rust 不需要 Proactor

Asio 选 Proactor 是为了统一 IOCP 和 epoll 的 API。Rust 的做法不同:

  1. mio 选 Reactor:更自然地匹配 epoll/kqueue;IOCP 的 Proactor 语义在 mio 内部适配(通过 AFD 轮询模拟 readiness)
  2. async/await 让 Reactor 写起来像 Proactor:用户代码写 let n = socket.read(&mut buf).await,看起来像 Proactor(「帮我读,读完告诉我」),但底层是 Reactor(mio 通知就绪 → tokio 驱动执行 read → 结果返回给 Future)
  3. 所有权系统消除了 Proactor 的缓冲区生命周期问题:Asio 的 async_read 需要用户保证 buffer 在操作完成前有效(共享指针模式),Rust 的 read(&mut buf).await 通过借用检查器在编译期保证 buffer 活得够久

文档索引

mio(I/O 事件通知)

文档核心内容
mio 是什么设计哲学、为什么选 Reactor
核心架构Poll / Token / Interest / Events / Source trait
平台后端epoll / kqueue / IOCP 适配细节
为什么不直接用 miomio 的局限与 tokio 的补充
关键设计决策Token vs callback、强制非阻塞、无全局状态
代码示例mio / tokio / Asio 三方对比

tokio(异步运行时)

文档核心内容
运行时设计work-stealing 调度器、与 Asio/Go 对比
任务系统spawn / JoinHandle / 协作式调度 / JoinSet
I/O 与同步原语I/O 驱动、时间轮、Mutex/channel、select!
陷阱与实践10 大陷阱、优雅关闭、tracing

tower(中间件抽象)

文档核心内容
Service traitpoll_ready + call 两步协议、背压
Layer 与 ServiceBuilder洋葱模型、组合机制
内置中间件RateLimit / Retry / Timeout / Buffer
tower-httpTrace / Compression / CORS

hyper(HTTP 协议)

文档核心内容
hyper 与 1.0 迁移0.14 vs 1.0 / hyper-util
Body trait流式 body 设计
架构关系hyper / tower / axum 如何协作

axum(Web 框架)

文档核心内容
设计哲学tower 原生、零宏路由、编译期提取
Handler 与 ExtractorFromRequest / IntoResponse / 类型魔法
中间件与生产实践中间件集成、错误处理、测试

C++ Asio(对照组)

文档核心内容
Proactor 模式Reactor vs Proactor 设计选择
io_context执行模型、executor 演进
组件拆分strand / timer / socket / buffer
异步模型演进完成令牌机制
OS I/O 多路复用epoll / kqueue / IOCP 统一
陷阱与实践10 大陷阱、生产 checklist

推荐阅读顺序

如果你来自 C++ Asio 背景

  1. Asio Proactor 模式 → mio 为什么选 Reactor(理解设计分歧)
  2. Asio io_context → tokio 运行时(理解调度模型差异)
  3. Asio 组件 → tokio I/O + 同步原语(理解组件对应关系)
  4. tower Service trait(Asio 没有的层——中间件抽象)
  5. hyper → axum(Asio 没有的层——HTTP 框架)

如果你从零开始学 Rust 异步

  1. mio 是什么 → 为什么不直接用 mio(建立底层认知)
  2. tokio 运行时 → 任务系统 → I/O 与同步原语(理解运行时全貌)
  3. tower Service trait → Layer → 内置中间件(理解中间件范式)
  4. hyper Body trait → axum 设计哲学 → Handler 与 Extractor(理解 Web 层)
  5. tokio 陷阱 → axum 中间件与实践(实战储备)

分享这篇文章:

上一篇
云原生基础:Twelve-Factor App 作为应用设计契约
下一篇
Rust 基础:类型转换 as、From/Into 与 Turbofish