Monoio: 字节跳动开源 Rust Runtime - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
ihciah
0.19D
0.03D
V2EX    分享创造

Monoio: 字节跳动开源 Rust Runtime

  •  8
     
  •   ihciah
    ihciah 2021-12-09 09:30:06 +08:00 10413 次点击
    这是一个创建于 1403 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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-bench-100B.png

    monoio-bench-1C-250conn-qps.png

    我们对比了 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 设计与实现

    49 条回复    2022-08-23 13:41:38 +08:00
    Mithril
        1
    Mithril  
       2021-12-09 09:33:12 +08:00   9
    BS:你们为了不学 C++也真是费尽心机了
    fyooo
        2
    fyooo  
       2021-12-09 09:40:47 +08:00   1
    谢谢分享,字节很多开源项目都充满干货啊
    ihciah
        3
    ihciah  
    OP
       2021-12-09 09:48:09 +08:00
    @Mithril 用 Rust 上线更安心~

    @fyooo 谢谢支持,也欢迎大家参与!
    PureWhiteWu
        4
    PureWhiteWu  
       2021-12-09 09:48:17 +08:00
    Monoio 之父 YYDS
    Kilerd
        5
    Kilerd  
       2021-12-09 09:55:01 +08:00
    thread-per-core 的一个问题在于没有 work-steal ,那么就很有可能存在一核干活,N 核围观的情况。这十分考验任务进哪个 thread 的调度。

    tokio 作为一个通用的 async runtime 必然是要设计成 work-steal 的。

    但是一个问题是,你们有没有试过你们的产品和 自己启动 thread ( thread 里面各自启动一个 tokio 的 single thread 的 rt ) 的性能比较呢? 这样的测试可能才是对等的。

    另外,Rust 现阶段跟 io-uring 并不是很搭,不知道你们是怎么解决 buffer 的安全性问题的。
    kernelerror
        6
    kernelerror  
       2021-12-09 09:55:48 +08:00 via Android
    支持
    RtfscRtfm
        7
    RtfscRtfm  
       2021-12-09 09:57:44 +08:00
    Monoio 之父 YYDS
    ihciah
        8
    ihciah  
    OP
       2021-12-09 10:00:52 +08:00
    @Kilerd 是的,我们的场景上和 Tokio 是不同的。
    可以看和 tokio 单线程的对比数据(这时其实主要差别就在于 epoll 和 io-uring 了)。
    buffer 我们采用的 Tokio-uring 的做法,直接拿所有权,用完还回去。
    CatCode
        9
    CatCode  
       2021-12-09 10:32:33 +08:00   1
    感谢开源
    Croxx
        10
    Croxx  
       2021-12-09 11:06:34 +08:00 via iPhone
    在 github 看到之后就在找作者的 twitter ,没想到在 v 站看到了
    coeru
        11
    coeru  
       2021-12-09 11:39:17 +08:00
    成功
    abcbuzhiming
        12
    abcbuzhiming  
       2021-12-09 11:52:02 +08:00   1
    @Mithril 我看了 rust 之后觉得 rust 的学习曲线没有比 c++低到哪里去,可能唯一的优势就是没有 C++那么多的特性
    libook
        13
    libook  
       2021-12-09 11:57:59 +08:00
    最近刚看完 Rust 的教程 ,不知道以后能不能用 Rust 写微服务。
    PureWhiteWu
        14
    PureWhiteWu  
       2021-12-09 11:59:46 +08:00
    @libook 当然能用,可以期待一下我们即将开源的微服务框架~
    DonaidTrump
        15
    DonaidTrump  
       2021-12-09 12:53:25 +08:00 via iPhone
    支持。话说这是孵化的产品,还是已经再生产环境使用了?
    mywaiting
        16
    mywaiting  
       2021-12-09 12:58:27 +08:00   2
    虽然看不懂,但是看到 Rust 写的我就想点赞
    ihciah
        17
    ihciah  
    OP
       2021-12-09 13:17:12 +08:00
    @tulongtou 目前公司内部计划基于这套 Runtime 做下一代高性能 MeshProxy ,但尚无生产实际使用。开源出来也是希望能够和大家一起建设生态:)
    CSM
        18
    CSM  
       2021-12-09 13:25:43 +08:00   2
    提个建议,叫 Rust async runtime ,只看 Rust runtime 容易摸不着头脑
    araaaa
        19
    araaaa  
       2021-12-09 13:29:07 +08:00 via iPhone
    啥时候支持多平台
    DonaidTrump
        20
    DonaidTrump  
       2021-12-09 14:01:20 +08:00   1
    @ihciah 挺好的,希望项目能长期发现下去。
    feather12315
        21
    feather12315  
       2021-12-09 14:04:31 +08:00 via Android
    @araaaa #19 不可能的,io uring 是 Linux 独有的
    nameyuka
        22
    nameyukan  
       2021-12-09 14:06:41 +08:00
    看了下代码,咋都没测试的,质量怎么保证?
    ScepterZ
        23
    ScepterZ  
       2021-12-09 14:07:47 +08:00
    不懂就问,压测曲线上,蓝色的在 40000 的时候 cpu 就 100%了,然后在此基础上 150%的 qps ,到 60000 的时候,延迟基本没变化,这合理吗
    codehz
        24
    codehz  
       2021-12-09 14:13:18 +08:00 via Android
    tinkerer
        25
    tinkerer  
       2021-12-09 14:48:06 +08:00   1
    谢谢你们的贡献
    ihciah
        26
    ihciah  
    OP
       2021-12-09 16:10:28 +08:00
    @ScepterZ 因为连接数是固定的,所以在达不到设定的 QPS limit (限制做在客户端)时,在服务端的感知是完全一样的。

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

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

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

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

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

    @kerro1990

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

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

    谢谢批评,目前文档确实欠缺。当前也并不是生产 ready 的,我们明确说了项目仍处于非常早期的阶段,相信你从 0.0.x 的版本号上也能看出来。
    但我觉得,开源并不是一定要先做到完美。众人拾柴火焰高,我们希望能够和志同道合的人、有同样需求的人一起来把它变完美。作为一个不涉及公司业务细节的通用组件,开源开发并不会带来任何不便;反而在大家的监督和 review 下 commit 质量会更好。
    neon0
        41
    neon0  
       2021-12-10 13:55:37 +08:00
    @kernelerror 你的头像是哪方卧底
    whimsySun
        42
    whimsySun  
       2021-12-10 15:46:25 +08:00
    挺感兴趣的,monoio 是不是也适合用来做边缘网关,看压测说大连接的情况下性能好雨 envoy
    ihciah
        43
    ihciah  
    OP
       2021-12-10 20:15:52 +08:00
    @whimsySun 这个确实是我们的目标场景(我们组主要做 ServiceMesh )。Edge Proxy 和 Mesh Proxy 都是比较理想的应用场景。
    whimsySun
        44
    whimsySun  
       2021-12-10 21:03:54 +08:00 via iPhone
    @ihciah 能不能加下 tg ,我们有在弄 edge proxy ,也有在接 istio
    ihciah
        45
    ihciah  
    OP
       2021-12-10 21:54:51 +08:00 via iPhone
    @whimsySun 场景是合适,我们内部也决定做,但是还没做出来 (tg 同名
    kkocdko
        46
    kkocdko  
       2021-12-12 11:21:20 +08:00 via Android
    太强啦~
    昨天才在 rustcc 那边看到,没想到作者也在 V 站
    pupie
        47
    pupie  
       2021-12-13 10:52:19 +08:00
    感谢开源~
    orafy
        48
    orafy  
       2022-02-14 09:50:28 +08:00
    Service Mesh 有一个优化方向可以参考 Cilium ,更多的利用 XDP 。
    兼容性比 DPDK 的转发层好。

    Kernel bypass 的技术能 10~50 倍于 io-uring/epoll
    novolunt
        49
    novolunt  
       2022-08-23 13:41:38 +08:00
    @libook
    @PureWhiteWu
    可以使用 ebpf 做 service mesh ,cilium 的 mesh 方案
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2620 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 06:46 PVG 14:46 LAX 23:46 JFK 02:46
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86