干货分享|Web 和云开发,Rust 会起飞?
发布时间:2023-08-17 14:08:27
去年,Web 开发公司 Mainmatter 对 Web 版 Rust 进行了战略押注,并发起了 EuroRust 会议,加入了 Rust 基金会,同时正在内部以及开源领域从事许多 Rust 项目。Mainmatter 非常乐观地认为 Rust 将在未来几个月和几年内在 Web 和云空间中起飞,并认为 Rust 是迈向 Web 开发新时代的第一步,开发人员可以利用这项技术,在不放弃开发人员经验和生产力的情况下,达到更高的、以前难以想象的效率、稳定性、可靠性和可维护性水平。这篇文章意在分享为什么 Mainmatter 有信心作这一押注,以及为什么我们相信 Rust 在 Web 和云领域拥有美好的未来。大厂偏爱,Rust 的未来
Rust 自从大约十年前登台以来,就受到了很多开发人员的关注和喜爱。不仅开发人员喜欢这门语言,大公司的决策者也认为 Rust 是一项伟大的技术,并且在过去几年里,该语言在整个行业得到了广泛采用。AWS 在其平台上大量使用 Rust ,Google 在 Android 中使用它,Microsoft 在 Windows 中使用它。从本质上讲,Rust 有望在以前使用的许多领域取代 C 和 C++:系统编程、操作系统、各种嵌入式系统、低级工具以及游戏和游戏引擎。当然,除了以上这些,未来具有更大潜力的领域是 Web 和云。Rust 给这两个领域带来了无限想象的后端提升空间。一旦后端的开发提升到一个新的水平,就能让团队能够访问以前无法实现的功能。尽管 Rust 还很年轻,但已经看到很多公司在 Web 和云中成功使用 Rust,比如:Truelayer、Discord、Temporal、Nando's、svix、Wingback 等等。值得一提的是,谷歌多年来也一直大力采用 Rust,最近表示,与他们使用的任何其他语言相比,他们并没有真正看到 Rust 的生产力损失。Rust 做 Web 的雄心
虽然相对年轻,毕竟距离 1.0 发布,Rust 的生态系统也只走过了 8 年。但 Rust 以及其 Web 生态已经达到了一定的成熟度,足够使其成为构建真实应用程序的可行选择。正如 arewewebyet.org 所证实的,Rust 显然已经为 Web 做好了准备:首先,有 tokio,一个异步运行时,它是 Web 应用程序的坚实且高性能的基础;其次,最重要的是,Rust 已经有了成熟且维护良好的 Web 框架,例如 axum 和 actix-web。所有相关数据存储以及 ORM 都有成熟的驱动程序;最后,可以找到涵盖构建 Web 应用程序的所有其他相关方面的库,例如(反)序列化、国际化、模板化、可观察性等。
总的来说,Rust 的雄心勃勃,构建 Web 后端提供了坚实而稳定的构建块。当然,有人可能会问:我为什么要换 Rust?对于已经使用 Ruby、Java、Elixir、TypeScript、Go 或其他任何语言的团队而言,换 Rust 有哪些好处吗?有两个关键方面使 Rust 成为 Web 构建的绝佳选择:一是它的效率和性能;二是其类型系统带来的可靠性和可维护性带来的好处。Rust 以其高效和高性能而闻名。它将轻松超越 Web 应用程序常用的 JavaScript、Ruby、Python 等语言几个数量级。其他语言可能具有更高的性能上限(例如 Java 或 C# 或 Go),但你需要投入大量的工程精力才能接近 Rust 工具包开箱即用提供的性能水平。此外,Rust 还有一个关键优势:它不捆绑垃圾收集器。垃圾收集语言可以很快,但它们不能始终一致性地表现出色。垃圾收集器将引入暂停(pause)以释放未使用的内存,从而对应用程序的尾部延迟产生负面影响。而 Rust 不存在这个问题:它可以提供一致的性能,而不会出现这些峰值。C 和 C++ 是唯一能够实现如此稳定和一致性能的其他语言。不幸的是,这两种语言往往搬起石头砸自己脚,处处是陷阱,特别是在手动内存管理时。正如 Linux 的创始人 Linus Torvalds 所说:“它离硬件太近了,你可以用它做任何事情。这很危险。就像玩杂耍电锯一样。我还发现它确实有很多陷阱,而且很容易被忽视。
由于 C 和 C++ 的这些危险,除了这两种语言的专家或拥有专家团队时才能使用。否则,你得到的就是一个不稳定且充满安全漏洞的系统。同时,别忘了,在 Web 领域,很少人具备这种专业知识,因为每个人大多都使用非常不同的语言,如 JavaScript、Python、Ruby、Elixir 等。反而 Rust 就不会遇到同样的陷阱,使开发人员能够以以前的效率水平构建软件。Rust 通常会比用于构建 Web 后端的其他技术的性能好几个数量级,同时保持显着较低的内存占用。当然,如果与其他技术相比, Rust Web 服务器可以在一小部分时间内响应请求,这也意味着它可以用更少的服务器响应相同数量的请求,这又意味着更少的托管成本。这对于中小型产品和公司来说,减少托管的云服务器数量,就意味每月就可以轻松减少不菲的费用。我们的 Python 服务平均约为 50 个请求/秒,NodeJS 约为 100 个请求/秒,Rust 约为 690 个请求/秒。我们可以在通常托管单个 Python 服务的 k8 EKS 节点上安装 4 个 Rust 服务。——Reddit 某用户
然而,成本节省还只是好处之一,使用更少的服务器也意味着使用更少的能源。尽管使用可再生能源运行数据中心固然很好,但最绿色的能源仍然是我们不使用的能源。Rust 或许不能解决气候危机,但这里要承认的是,运行我们编写的软件,也会真真切切地消耗资源,从而对现实世界产生影响。软件行业往往会忘记这一点——如果我们能够更有效地利用资源,并以更少的投入获得相同的产出,这是选择技术时的一个重要考虑。虽然性能和效率很重要,但在许多情况下,可能更相关的原因则是 Rust 的强类型系统所带来的可靠性和可维护性收益。像这样的代码片段对于 Web 应用程序(Ruby on Rails)来说是相当典型的: def activate(activation_date) self.activation_date = activation_date
虽然这段代码非常简洁且易于阅读,并且编写这样的代码可以让你快速实现目标,但也存在问题。在这个的示例中,虽然我们可以看到用户的属性,但我们不知道这些属性周围可能有什么规则(例如,如果 active 是 true,则 activation_date 可能也必须设置?如果 active 是 false,则大概 activation_date 应该是 nil?)。为了验证这些假设,我们必须研究该 activate 方法的实现,这意味着需要付出相对较高的努力才能获取信息。查看该 activate 方法的调用,我们无法知道它是否会引发错误,或者我们应该在哪个时区中度过时间。虽然 Ruby 可能有点极端,但考虑到其众所周知的灵活性,许多这些问题在其他语言中也存在。让我们以 Java 为例。我们仍然无法在类型系统中对围绕 active 和 activation_date 属性的规则进行编码,即使可以 null,我们也有 NullPointerException 在运行时获取 s 的风险。随着代码库的增长和开发团队的壮大,或者只是随着一些人离开和加入而发生变化。从事代码库工作的每个人都对整个应用程序以及整个代码库中所做的所有隐式假设都有一个完美的心智模型,但这很难做到,相反,理解这些概念需要人们认真阅读遗留代码。这不仅降低了效率,而且还可能导致生产中的错误率增加。与上面相同的代码片段,但在 Rust 中更加清晰和富有表现力: activation_date: DateTime<Utc>, fn activate(&self, activation_date: DateTime<Utc>) -> Result<(), DBError> { User::Inactive { name } => { let new_user = User::Active { activation_date: activation_date,