Monoio: 字节跳动开源 Rust Runtime

2021-12-09 09:30:06 +08:00
 ihciah

Monoio 是字节跳动服务框架组开源的基于 io-uring 的 thread-per-core 模型高性能 Rust Runtime ,旨在为高性能网络中间件等场景提供必要的运行时。

项目仓库: https://github.com/bytedance/monoio

背景

过去,高性能网络中间件或服务器往往使用 C/C++ 编写,比如我们常见的 Envoy 和 Nginx 。它们往往以非常直接的方式和操作系统交互,并且得益于没有垃圾收集机制,相比有 GC 的语言(如 Golang 和 Java ),额外开销十分低,延迟稳定。

但是开发这类组件对开发者的专业水平有较高的要求,编程范式上对开发者心智负担巨大,稍有不慎就会造成非预期的后果。举例来说,在 C++ 中要完成一次异步的网络请求,需要将整个流程按照异步点拆分成独立的纯同步函数,并以 callback 的形式将其串联——这一来大大降低了其可读性,二来状态转换和管理容易出错;并且对变量生命周期需要精细管理,否则就会出现悬垂指针等内存问题。

为什么不试试神奇的 Rust 呢? Rust 语言通过引入所有权模型,在不引入垃圾回收的情况下保证了内存安全;并且通过语言内置的异步抽象,支持了 async + await 的异步编程模式。使用一个优秀的 Runtime ,即可像写 Golang 一样流畅地在 Rust 中平铺直叙地写异步代码——而性能并不输于 C++。

Rust Runtime 与 thread-per-core 模型

与 Golang 不同,Rust 语言中标准库并没有提供异步运行时(Runtime),只提供了必要的结构抽象。Runtime 负责与操作系统打交道,并对齐标准库的 Future 和 Waker 等定义,用户可以自主选择 Runtime 。

当前被广泛使用的 Runtime 是 Tokio ,它提供了类似 Golang 调度器的实现,用户的 Task 可以在多个线程之间被调度,较为有效地利用了多核心的性能。

但问题也随之而来:在部分强依赖高性能低延迟的场景下,调度带来的开销反而是用户不希望看到的。在核心数较多的情况下,调度开销反而会抵消调度带来的好处。

Nginx 和 Envoy 这类组件往往使用 thread-per-core 模型,即多少核心就运行多少线程,一个任务一旦被一个线程所接收,它后续的处理则都在该线程上。这种做法下几乎没有跨线程的开销,提升了 CPU 利用率,可以较好地保持系统的线性扩展性。此外,由于没有跨线程,处理逻辑也可以尽可能地利用 thread local 的便利,多数时候无需加锁便可操作共享数据。

面向这类场景,Monoio 基于 io-uring 致力于提供最佳的性能;另外,我们还定义了一个更适合 io-uring 的 IO trait 。

性能

我们对比了 Monoio 、Tokio 和 Glommio (另一个类似的 Runtime ,但在性能目标上不如 Monoio 激进)。

在绝大多数测试中,Monoio 都具有更低的延迟和更高的吞吐。对比 Tokio ,在多核场景下 Monoio 可以提供 2 到 3 倍的性能提升(原因主要在于模型上,没有了跨线程同步开销);而对比 Glommio ,我们可以在降低延迟的同时,节省约 1/4 到 1/3 的 CPU 占用(性能提升在于更优的调度实现,io-uring 批量 submit )。

更进一步的测试报告和设计上的权衡在 Github Repo 中有详细的文档。

另外,我们还对比了生产中使用的(epoll based) Nginx ,在 Proxy 场景下基于 Monoio 写的 TCP 代理可以获得差不多的性能(连接数较多时 Monoio 性能优于 Nginx ,较少时差于 Nginx ,数据整体上差不多)。与 Envoy 的 TCP Proxy 对比也表明 Monoio 有非常明显的性能优势。

结语

Monoio 提供了 thread-per-core 场景下最高性能的 Runtime 实现。我们的目标是能够让 Rust 在高性能场景下成为替换 C/C++ 的更好选择。目前字节已经开始基于 Rust 和 Monoio 构建下一代 Service Mesh 。

当然,没有什么 Runtime 是绝对最佳的选择,Runtime 的选型还是要根据具体的业务场景来。希望我们的 Monoio 可以给某些场景用户多一种选择。

在 Monoio 的设计和实现中我们大量参考了 Tokio 等同类产品,感谢这些项目的贡献者;也希望 Monoio 能够在大家的共同努力下变得更加完善更加易用。

参考资料

另外,在开发过程中我也总结了一些东西,写成了几篇博客,感兴趣可以看这里:Rust Runtime 设计与实现

9686 次点击
所在节点    分享创造
49 条回复
feather12315
2021-12-09 14:04:31 +08:00
@araaaa #19 不可能的,io uring 是 Linux 独有的
nameyukan
2021-12-09 14:06:41 +08:00
看了下代码,咋都没测试的,质量怎么保证?
ScepterZ
2021-12-09 14:07:47 +08:00
不懂就问,压测曲线上,蓝色的在 40000 的时候 cpu 就 100%了,然后在此基础上 150%的 qps ,到 60000 的时候,延迟基本没变化,这合理吗
codehz
2021-12-09 14:13:18 +08:00
tinkerer
2021-12-09 14:48:06 +08:00
谢谢你们的贡献
ihciah
2021-12-09 16:10:28 +08:00
@ScepterZ 因为连接数是固定的,所以在达不到设定的 QPS limit (限制做在客户端)时,在服务端的感知是完全一样的。

@nameyukan 感谢批评,测试这块后续逐渐会逐渐补齐。目前 unsafe 不太多,通过 Rust 本身基本可以保证没有内存问题。逻辑问题确实需要,这块目前在快速推进还不完善。

@araaaa windows 暂时不会支持,后续可能会通过引入 mio 来支持 mac 和无 iouring 的 linux 。
Kilerd
2021-12-09 16:50:15 +08:00
@ihciah tokio-uring 我印象中他为了保证所有权的安全,其实是把数据从内核态拷贝了一份到用户态,本质上并没有「真正完全」使用 io-uring 的优势(后续有没有更改我没有太了解了)

请问你们是如何解决这个问题的?
ihciah
2021-12-09 17:20:55 +08:00
@Kilerd 没有拷贝,我们这部分设计(以及部分代码)其实是直接从 tokio-uring 里搬的,不过我们基于 GAT 把这部分抽成了 trait 。
带所有权的接口设计就是用户扔所有权进来,io 完成时再扔回去。这样可以保证在 sq 推进去之后 sq 中的 buffer 指针一直是有效的。
Kilerd
2021-12-09 17:32:56 +08:00
@ihciah 多谢解答,谢谢。
Mistwave
2021-12-09 17:53:48 +08:00
赞 字节内部 rust 用的广泛吗?
kerro1990
2021-12-09 20:10:37 +08:00
@Mistwave 一看就是 KPI 项目,字节内部都不用
kerro1990
2021-12-09 20:13:34 +08:00
@Kilerd KPI 项目无疑了,字节内部大部分都是用 go 和 py
ihciah
2021-12-09 20:46:13 +08:00
@Mistwave

并不广泛,在业务侧用户很少。我们认为,一来是因为业务不那么 care 性能,而 rust 上手成本又很高,二来是因为想用也用不了,因为 rpc 等组件没有。我们前阵子在做这堆组件(我之前有帖子分享做 rpc 框架),给想用却没法用的业务用的机会。现在业务基本能用 rust 写了,不过使用者仍不算多。

但是我们认为在基础架构内部 rust 的未来还是很美好的。内核组已经有一些应用了,我们 Mesh 这边也计划造下一代基于 rust 的数据面代理,公司内的 rust 群也有接近 2000 人。

@kerro1990

你不用不代表没人用哦。
Kilerd
2021-12-09 21:20:27 +08:00
@kerro1990 可能是,也可能不是。 字节内部还是有不少团队在用 rust 的,但是业务团队应该很少就是了。

开源本意很好,但是还是要看内部发展和开源部分会不会分叉。 是不是 kpi 开源还要看之后的维护,目前看起来也只够字节内部部分团队使用而已,而且不太兼容市面上 tokio 和 async-std 的所有生态,生态很重要,async-std 追赶了一年多还影响不到 tokio 的地位,这个作品就更加不可能了。
Suclogger
2021-12-09 21:57:13 +08:00
rust 生态又添一个巨佬
linshenqi
2021-12-09 22:33:45 +08:00
支持下~很久以前就想学 rust ,但一直用 golang 就没在搞了。。
ihciah
2021-12-09 23:16:57 +08:00
@Kilerd 是的,我们开源的本意也是为了一起建设这类基于完成通知 IO 的生态。这个 rt 只面向限定场景,并且至少我们内部确实需要用,所以后续也会持续投入。
statumer
2021-12-10 10:47:41 +08:00
太牛啦,一直在找 rust 用 io uring 一个比较好的方案
nameyukan
2021-12-10 11:41:50 +08:00
@ihciah 在服务和质量没有达到一定程度,现在开源出来是否过早,刚看了一眼也缺少一些案例和文档。从为开发者负责的角度来讲和后续自身维护的角度,我都觉得太着急了一点。
ihciah
2021-12-10 13:12:38 +08:00
@nameyukan

谢谢批评,目前文档确实欠缺。当前也并不是生产 ready 的,我们明确说了项目仍处于非常早期的阶段,相信你从 0.0.x 的版本号上也能看出来。
但我觉得,开源并不是一定要先做到完美。众人拾柴火焰高,我们希望能够和志同道合的人、有同样需求的人一起来把它变完美。作为一个不涉及公司业务细节的通用组件,开源开发并不会带来任何不便;反而在大家的监督和 review 下 commit 质量会更好。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/821027

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX