乐趣区

关于rust:Rust-新手学习指南为什么学-Rust如何快速上手-Volo-框架

CloudWeGo Study Group 是由 CloudWeGo 社区发动的学习小组,发展以 30 天为一期的源码解读和学习流动,帮忙新成员融入社区圈子,和社区 Committer 互动交换,并学习上手 CloudWeGo 几大框架我的项目。

CSG 流动第三期次要以 学习 Rust 语言 为背景,对 Volo 和 Monoio 源码进行解读。本期流动期间将会安顿 4 期直播分享,围绕的主题别离为:

  • Rust 语言的个性、CloudWeGo 抉择 Rust 语言进行深刻摸索的起因以及 Volo 框架产生的初衷;
  • Rustcc 聊天室:Volo 框架的设计准则、如何上手以及框架设计特点;
  • Go 工程师如何尝试应用 Rust,如何从 Go 转型 Rust、调用 Rust 办法,Go 尝试和迁徙应用 Volo 框架的应用老本和长处;
  • 基于 io-uring 的高性能 Rust Runtime:Monoio 的技术特点及设计实现。

本文整顿自 CSG 第三期第一场直播中字节跳动架构研发工程师 刘捷 分享内容。

回放链接:https://meetings.feishu.cn/s/…

01 嘉宾介绍

本次分享内容次要分为以下两个局部:

  1. CloudWeGo 抉择 Rust 语言进行深刻摸索的起因;
  2. 创立 RPC 框架 Volo 的起因。

02 前言

大家可能或多或少都接触过 Rust 语言的相干信息。

前段时间,微软 Azure CTO 呐喊应用 Rust 代替 C/C++。Elon Mask 说本人是 Rust 的粉丝,然而却抉择应用 C++。这种对于语言的口水战是长久以来都是不可避免的,大家感性对待就好。

在 Rust 语言畛域,咱们也可能常常会听到某个公司用 Rust 重写了某个我的项目,取得了哪些收益。毕竟在 Rust 语言外面有一句玩笑话,“所有能用 Rust 实现的,终将会用 Rust 重写”。

咱们也常常会听到对于 Rust 语言的初创公司取得融资的音讯。

除了这些在 Rust 语言编写之外的信息,咱们也会接触到编写 Rust 的相干信息,比方与编译器斗智斗勇、泛型束缚过长以及弱小的宏编程。

03 深刻摸索 Rust 的起因

通过理解以上信息,大家曾经有了对于 Rust 语言的初印象。那么 CloudWeGo 为什么要抉择 Rust 这门语言进行深刻摸索呢?这不得不提到 Rust 的倒退历程。

Rust 倒退历程

Rust 语言由 Graydon Hoare 私人研发,他是专门给语言开发编译器和工具集的工程师,他心愿开发一种保障平安的同时又能领有高性能的语言。2006 年,他开始进行研发。2008 年,他被 Mozilla 聘用,过后 Mozilla 要开发 Servo 引擎,想要保障平安的同时又能领有高性能,于是他们一拍即合,Graydon Hoare 失去了 Mozilla 的资助。2010 年,Rust 语言首次公布 0.1.0 版本,用于 Servo 引擎的研发。2010 – 2015 年期间,Rust 经验了 GC 移除等一系列演进,以保障高性能。2015 年,Rust 公布 1.0 版本,这也示意正式官宣 Rust 趋于稳定。2015 – 2018 年,Rust 达成了生产力的承诺,也就是它的工具文档还有编译器变得更加智能,也对开发者更加敌对了。2018 – 2021 年,Rust 做了更多异步生态的欠缺,这也使得这门语言慢慢走向成熟。

Rust in 2022

2022 年曾经是 Rust 间断第七年位居 Stack Overflow 最受开发者青睐的编程语言榜榜首。

为了给治理和开发 Rust 我的项目的维护者提供一些反对,Rust 成立了基金会。有了 AWS、谷歌这些大公司的反对,Rust 的倒退也有了肯定的保障。同时,Rust 行将融入到 Linux 6.1 版本中,除了 C 语言之外,Rust 是 Linux 内核迄今为止承受的惟一语言,这足以看出 Rust 在业界的重量级和影响力。

此外,作为 WebAssembly 畛域的首选语言,由 Rust 编写的 WebAssembly 运行时 Wasmtime 公布了 1.0 版本,这也意味着它达到了稳固状态和生产可用性。

最近 Reddit 的论坛上 Rust 的订阅人数冲破了 200K,首次超过了 Go 语言的订阅者人数。

Rust 2024

Rust 的将来倒退会是什么样子的呢?借助 Rust 官网团队成员的一句话来阐明,“the year of everywhere”,也就是说应用 Rust 语言编写的开源我的项目会有爆发性的增长。那么为什么能够预测它会被大范畴应用呢?这齐全得益于 Rust 对于易用性的建设布局。2021 – 2024 年,Rust 有一个 2024 布局,主题叫做 Scaling Enpowerment(扩大受权)。之所以取这个名字,是因为 Rust 有一个指标——“empower everyone to build reliable and efficient software”。Rust 最关注也是大家常常诟病的一点,就是 Rust 的整个学习曲线十分平缓,所以在这个布局中写道“Flatten the learning curve”。

Rust 劣势

CloudWeGo 抉择 Rust 语言进行摸索,是因为 Rust 语言具备以下三大个性。

高性能

  • 基于 RAII 的内存治理

RAII 是将内存资源和对象绑定在一起。在创建对象时将资源分配进来,在销毁对象时把内存资源间接开释掉。相比于 JAVA / Go 等带有 GC 的语言,在 Rust 语言中,生效对象绝对应的内存资源能够失去立马开释,不须要期待某一个工夫点由 GC 进行对立的内存回收,防止了性能损失。

  • 严格的束缚

Rust 语言的译器对程序员的代码要求会更严格,除了实现失常性能之外,它还能获取到一些额定的编译信息,以辅助编译器做极致的优化。

  • 零老本形象

零老本形象能够了解为你用不到性能,就不须要为之付出代价。例如,Rust 这门语言是简直没有运行时的,也就是说你在实现一个纯同步代码的性能时,产物外面不会蕴含异步运行时的开销。

下图是从各语言 Benchmark 外面截取的纯计算 case。能够看出 Rust 的性能是十分优良的,能够与 Go 语言、C++ 等相媲美。

可靠性

内存平安

内存平安是由两方面保障的,别离是所有权和生命周期。

  • 所有权

所有权指的就是任何资源有且只能有一个绑定对象。如下图所示,这相当于栈上有一个 S1 指针,指向了堆下面的一块内存资源。之后把 S1 复制给 S2,这个行为在不同语言中有不同的解决形式。在其余语言中,这一次的复制行为就会默认是一次拷贝,此时 S1 和 S2 都能够拜访那一块堆上的内存资源。然而在 Rust 语言中,这是一次挪动语义,也就是说这次复制把这一块内存资源的所有权从 S1 转移到了 S2,S1 也会因而生效而无奈应用。

所以把它打印进去应用的时候,编译器就会报错,这个值曾经被挪动了。这解决了内存平安中的第一个痛点,即对于同一块内存资源的二次开释问题。

  • 生命周期

生命周期是对于援用的限度,它保障的是被援用的对象存活工夫肯定长于援用者。这就意味着你援用的对象肯定是无效的。如下图所示,r 援用了 x,然而在第六行对 r 进行操作的时候,x 曾经在大括号的作用域外面沦亡了。

此时编译器也会报错。这就解决了内存平安中的第二个痛点———悬垂指针的问题。

并发平安

Rust 语言中是通过 Send 和 Sync 这两个标记的 Trait 实现的,Trait 能够了解为编程语言外面的一个接口。Send 和 Sync 外面都是没有任何办法申明以及办法体的,所以二者仅仅是作为标记信息提供给编译器,辅助编译器回绝一些线程不平安的代码。

  • Send: 实现 Send 的类型能够在多线程间转移所有权。

这个回绝的过程是怎么的呢?以在并发平安里最常见的 Data Race 为例,在不同线程间对同一个变量进行读写的数据争用,下图中 spawn 办法代表的含意是在 Rust 外面开始一个线程。

咱们能够看到它对于函数 F、类型 T 都有 Send 的束缚。这个 Send 的意义是实现 Send 类型,它能够在多线程间转移所有权,也就是说当初有线程 A 和线程 B,如果 T 的所有权从线程 A 转移到了线程 B,那么能够防止线程 A 和线程 B 同时对 T 进行读写操作,免得产生数据争用。

  • Sync: 实现 Sync 的类型能够在多线程间共享援用。

类型 T 所映射的是援用,这就是 Sync 这个标记能够施展的作用。如果是一个援用的类型须要实现 Send,那么就必须保障这个类型实现了 Sync 标记,以此防止数据竞争。

想理解更多对于 Send 和 Sync,能够查看下方链接。

The Rustonomicon: https://doc.rust-lang.org/nom…

生产力

Rust 语言是一门工程实际语言。它不须要遵循某一个特定的编程范式,开发这门语言的编程人员也同时在用这门语言实现一些生产工作。因而 Rust 语言有以下四个特点:

  • 智能的编译器

考察钻研表明,因为 Rust 语言的编译器报错信息更加详尽智能,应用 Rust 语言的开发者在开发过程中 Stack Overflow 应用更少一些。

  • 欠缺的文档

Rust 秉持“正文即文档”的理念。如果你想用某个库实现肯定的性能,通常依照它的示例阐明就能够疾速上手。

  • 齐全的工具链

Rust 是一个多平台反对的语言。

  • 成熟的包治理

它能够帮忙你更好地解决一些依赖。而且每当遇到一个新我的项目,你可能疾速找到一个入口去上手。

最初,最重要的一点是,如果应用 Rust 这门语言,你齐全能够信任别人的代码。因为如果他人的代码里有内存平安或者并发平安问题,根本都是编译不过的。

Benefits

理解 Rust 这门语言的三大劣势后,我从集体的角度登程,分享一些 Rust 语言值得被抉择的理由。

第一,Rust 帮忙你成为更好的程序员。Rust 这门语言足够底层,毕竟它能够融入到 Linux 内核中。在编写 Rust 的过程中,咱们不可避免地会接触到一些底层相干的常识。此外,Rust 的编译器非严格。在写代码的过程中,它会强制你去思考,从你所写的代码始终思考到内存堆栈援用、变量作用域等一系列内容。

第二,互联网的横蛮成长迟早会到止境,硬件的摩尔定律也在生效,后续可能就是存量优化的阶段,这个时候 Rust 这门语言就十分合时宜了。

第三,Rust 语言开发的我的项目会更稳固,也更好保护。因为它把运行时可能呈现的一些问题提前到编译期间进行解决。

Go or Rust

如果把 Go 语言和 Rust 语言进比照,后果会是怎么的呢?

如下图所示,无论是呈现工夫,倒退历程还是实用畛域,二者都相差不大,但二者并不是对抗关系,而是单干关系,它们是舍短取长的。毕竟语言只是工具,很多时候这个工具只有应用起来得心应手就能够。

2021 年 Go 开发者调研的报告显示,如果在新我的项目中抉择代替 Go 语言的另一种语言,抉择 Rust 语言的占比是最高的。

那么在应用这两种语言时应该如何抉择呢?

个别对于性能不敏感的利用、重 IO 的利用以及须要疾速开发疾速迭代胜过稳定性的利用,举荐应用 Go 语言,这种利用应用 Rust 并不会带来显著的收益。

而对于 须要极致性能、重计算 的利用,以及 须要稳定性并能承受肯定开发速度损失 的利用,举荐应用 Rust,Rust 在极致性能优化和安全性上的劣势能够在这类利用中得以施展。

在初步理解 Rust 语言后,对 Rust 语言感兴趣的同学可能心愿可能入手实际操作一下,所以接下来介绍一下 Rust 的装置和应用。

Rust 装置

  • 环境变量

咱们个别应用 RUSTUP 进行 Rust 工具链的装置和治理。个别能够先在你的零碎上配置这两个环境变量,上面是咱们团队保护的 RUSTUP 镜像,它能够减速在国内的下载。

RUSTUP_DIST_SERVER=”https://rsproxy.cn”
RUSTUP_UPDATE_ROOT=”https://rsproxy.cn/rustup”

  • 装置

装置分为以下两种状况:

第一,如果是 Linux 以及 MacOS 零碎,在终端执行这条命令即可。

Linux/MacOS:curl –proto ‘=https’ –tlsv1.2 -sSf https://rsproxycn/rustup-init.sh | sh

第二,如果是 Windows 零碎,下载下方链接中的 exe 可执行文件,后续依照默认的装置配置操作即可。

Windows:https://static.rust-lang.org/…

  • 验证

装置胜利的验证是在终端以及命令行外面输出 rustc -version,能够看到依照以下格局显示的最新稳固版本的版本号、对应的 Commit Hash 和 Commit 日期:

rustc x.y.z(abcabcabc yyyy-mm-dd)

这就代表曾经装置胜利。

环境配置

装置胜利后要进行环境配置,配置文件:

IDE

Rust 有 VS Code 和 Clion 两种编辑器可供选择。

VS Code

如下图所示,VS Code 只需装置 Rust Extension Pack 扩大包即可,其中最重要的是 rust-analyzer,它作为一个语言的服务器后端,可能帮忙你进行代码诊断。下图左侧的其余局部是比拟举荐的 Extension,能够用来辅助开发,其中 CodeLLDB 是 Rust 用来 Debug 的工具。

图中右侧是比拟举荐的 VS Code 设置。其中第三个设置在保留代码文件时,能够改成 clippy,也就是查看工具,它能够帮忙改善你的代码。将第四个设置中 build.rs 关上,能够帮忙你在执行我的项目代码之前编译执行 build.rs 的脚本。最初一个设置是对于 Rust 过程宏,可能帮忙你可能更好地写宏以及看他人写的宏。

Clion

Clion 须要装置 Rust 插件,装置之后关上图中所示 build.scripts 脚本选项即可。

Hello World

最初就能够正式进行 Hello World Demo 的应用了,能够依照以下步骤进行:

  • 创立新我的项目: cargo new he ello_world
  • 应用 VS Code 关上: codel hello_world
  • 跑起来: cargo run

咱们能够看到下图中 Hello World 的我的项目构造。src 是源码目录,main.rs 外面有 main 函数。

Cargo.toml 能够帮忙你治理包的信息以及依赖的引入。Cargo.lock 根本无需改变,它是 Cargo 主动生成的,能够帮忙你治理。target 外面是一些编译产物。

学习资源

  • The Book: https://doc.rust-lang.org/book/
  • Rust By Example: https://doc.rust-lang.org/rus…
  • Rustlings: https://github.com/rust-lang/…
  • Async Rust: https://rust-lang.github.io/a…
  • 汇总: https://github.com/ctjhoa/rus…

04 创立 Volo 的起因

Volo 是字节跳动服务框架团队研发的 轻量级、高性能、可扩展性强、易用性好 的 Rust RPC 框架,应用了 Rust 最新的 GAT 和 TAIT 个性。在字节外部,Volo 曾经落地多个业务和根底组件,并且获得了超预期的性能收益。

明确了 CloudWeGo 抉择 Rust 语言的起因以及 Rust 的劣势,我也具体论述一下发明 Volo 框架的起因。

生态现状

发明 Volo 框架与过后的生态状况是无关的。咱们过后调研过整个社区的生态,发现 没有生产可用的 Async Thrift 实现 。哪怕是社区中最成熟的 Tonic 框架,它的 服务治理性能也是比拟弱的,而且易用性也不够强 。更重要的是过后在 Rust 语言社区,还 没有基于 Generic Associated Type(GAT,Rust 语言最新的⼀个重量级 Feature)和 Type Alias Impl Trait(TAIT,另⼀个重量级 Feature)的设计

GAT & TAIT

GAT 和 TAIT 是目前只能在 Nightly Rust 上应用的个性,这两个个性也是 Rust 官网团队“2021 – 2024 三年布局”中三项重点工作其中两项。感兴趣的同学可自行进一步理解。

一个 Timeout 中间件

从下图咱们能够直观地看到,如果采纳之前社区的形式来编写一个最简略的 Timeout 中间件,在性能不损耗的状况下,代码量也是十分大的。在应用 GAT 和 TAIT 个性后,不仅代码量减少一倍,而且逻辑也更加简略清晰了。

Volo 劣势

易用性

Rust 以难学难用而闻名,咱们心愿尽可能地升高用户应用 Volo 框架和 Rust 语言编写微服务的难度,提供给用户最符合人体工程学和直觉的编码体验,因而咱们把框架易用性作为重要指标之一。只有让大家真正地应用 Volo,Volo 能力体现它的价值。所以 Volo 框架 基于 GAT 和 TAIT 个性,大大晋升了用户编写中间件的便当水平 。除此之外,咱们提供了 Volo  命令行工具生成默认 Layout,并且 Volo 的命令行工具 提供 IDL 治理的能力,这在业界是首例。咱们还提供了过程宏等可能再度升高 Service 编写难度的性能。当然还有很多其余的精心设计,比方很多 API 都是尽量以最符合人体工程学的形式给出的,也能够防止误用。

扩展性

  • 基于 Service 的形象

受害于 Rust 弱小的表白和形象能力,开发者能够基于非常灵活的 Service 形象,用对立的模式对 RPC 的元信息申请和响应做一些解决,比方服务发现、负载平衡等服务治理性能都是间接实现 Service 即可。

  • 基于 RPC 元信息的管制

另外,在咱们的框架设计中,所有框架行为都是受到 RPC 元信息管制的。因而咱们只有在 Service 中对 RPC 元信息进行批改,就能间接管制框架的行为,从而实现所需的性能。

下图是 Volo 自带的负载平衡中间件实现中最要害的一部分,即红色线框圈出的代码。只有把 Load Balance 选出来的地址放到 RPC 元信息中,就能够管制框架对这个对端地址发动申请。

高性能

如果过多议论框架的性能比照,容易引战。然而基于 Rust 语言的性能劣势以及 CloudWeGo 团队对于极致性能的谋求,咱们能够预想到 Volo 的性能也是十分高的。

如果把 Volo 和 Kitex 进行跨语言的比照也是不太偏心的,然而因为很多用户都关注性能数据,为了让使用者对 Volo 框架的性能有大抵的理解,咱们只给出比较简单的性能数据。

  • 在与 Kitex 雷同的测试条件(限度 4C)下,Volo 极限 QPS  为 35W。
  • 咱们外部正在验证基于 Monoio(CloudWeGo 开源的 Rust Async Runtime)的版本,极限 QPS 能够达到 44W。

理论业务收益

在框架的实际过程中,咱们尽可能在编译期就确定类型大小,防止在堆上的内存动态分配。同时在数据传输以及转换的过程中,咱们会尽量减少内存拷贝。我选取了由 Go 迁徙到 Volo 框架的两个业务,出现实在的业务落地收益。

1. 业务 A(Proxy 类)。A 业务的 IO 比拟多,是 IO bound 类型的业务,迁徙到 Volo 框架后的各方面数据如下:

  • CPU: -39.68%
  • MEM: -77.78%
  • P99: -76.67%
  • AVG: -70%

2. 业务 B(有大量业务逻辑)。业务 B 是一个计算密集型的业务,是 CPU bound 类型的业务,应用 Volo 框架后数据如下:

  • CPU: -43.75%
  • MEM: -69%
  • P99: -43.22%
  • AVG: -47.81%

因而咱们能够总结,不论是 IO bound 还是 CPO bound 类型的业务,应用 Volo 框架后 CPU、内存和延时指标都有显著的优化。

相干生态

随着 Volo 框架开源,一起开源的所有生态如下:

  • Volo 是 RPC 框架的名字,蕴含了 Volo-Thrift 和 Volo-gRPC 两局部。
  • Volo-rs 组织:Volo 的相干生态。
  • Pilota:Volo 应用的 Thrift 与 Protobuf 编译器及编解码的纯 Rust 实现。
  • Motore:Volo 参考 Tower 设计的,应用了 GAT 和 TAIT 的 middleware 形象层。
  • Metainfo:Volo 用于进行元信息透传的组件,定义了一套元信息透传的规范。

Volo 相干地址

Volo 的我的项目构造如下图红线框圈出局部所示。如果想对 Volo 做奉献,能够多多关注 volo-thrift/volo-grpc/volo。同时咱们也提供了大量的 Good First Issue,大家能够以练代学,参加到 Volo 的建设中来,咱们也会给大家提供一些详尽的帮忙。以下是所有相干生态的仓库地址。

欢送大家来提 Issue 或 PR,一起共建 Volo!

  • 官网: https://www.cloudwego.io/zh/d…
  • Good First Issue: https://github.com/cloudwego/…
  • Volo: https://github.com/cloudwego/…
  • Volo-rs: https://github.com/volo-rs
  • Pilota: https://github.com/cloudwego/…
  • Motore: https://github.com/cloudwego/…
  • Metainfo: https://github.com/cloudwego/…

Demo

Rust RPC 框架的调用链如下图所示:

具体调用 Demo 演示过程请参考直播视频回放链接:(从 41:18 处开始)

https://meetings.feishu.cn/s/…

Demo 相干官网文档:
https://www.cloudwego.io/zh/d…

以上内容整顿自 CloudWeGo 源码解读流动第三期第一场直播分享,获取 讲师 PPT 和回放视频,请关注 CloudWeGo 公众号,并在后盾回复关键词 “Volo”

我的项目地址

GitHub:https://github.com/cloudwego

官网:www.cloudwego.io

CSG 三期:https://mp.weixin.qq.com/s/vw…

退出移动版