我记得当我第一次尝试 Rust 时,我就爱上了它。
Rust就像继 JavaScript 和 NodeJS 之后的一股新鲜空气一样。TypeScript 让开发者体验变得更好,如果你仍然在写纯 JavaScript,你可能注定要暂时不成功。
我将在这儿和大家写一些关于类型的重要性。
回到 Rust。我对 Rust 的第一次体验,除了尝试使用ggez、bevy和wgpu构建自己的游戏之外,是在 Rust 中构建一个 Electron 应用程序可以调用的业务逻辑层,但是这个项目未见过光。但我也并不失望,因为我设法制作了两篇令人惊叹的内容,并在一次聚会和两次国际技术会议上展示了它们。
但我仍然想用 Rust 编写一个 Web 应用程序,因为正如他们所说:“任何可以用 Rust 编写的东西,都将用 Rust 重写一遍”。
在去年的11 月 1 号——我做到了!我启动了JustFax Online这一项目。JustFax Online 是一项服务,允许你发送一次性发送传真,无需创建帐户或承诺订阅。对于需要偶尔发送传真的人来说,这是一个完美的工具。最重要的是,就技术而言,JustFax 是一款 100% Rust 原生应用程序。
JustFax的架构
我们来谈谈JustFax的架构。它由两个操作系统进程组成:Web 服务器和负责发送传真的调度程序。
Web 服务器是用axum编写的,这是一个非常流行的 Web 框架。Axum构建于 Rust 之上tokio,这是 Rust 的异步运行时;hyper,这是 Rust 中的低级 HTTP 实现;还有tower,它是用于构建网络客户端和服务器的可重用组件的集合。
最重要的是,它使用tera模板引擎,其语法与 Jinja2 类似。存储由 SQLite 负责,通过rusqlite库处理。
调度程序进程只是一个无限循环,用于轮询数据库以便知道是否进行了更改。还有一些第三方集成,这里不做细述。
下面谈谈我用 Rust 构建 Web 应用程序的经验。
首先,我们将从好的部分开始。
内存使用情况。这显然是我从 Rust 获得的第一个优势。在部署第一个版本后不久,我还在X上发布了这张图片。
对,这是真事儿。一个 Web 应用程序加一个定时任务程序,全部封装supervisord在 Docker 的容器中,需要仅不到 30MB 的内存,秒杀那个 NodeJS了!
其实最重要的是安全。Rust 社区有一句话是这样说的:“如果符合要求,它就会运行。” 总体来说,这是真的。比如你可能会因反序列化第 3 方 API 响应而遇到运行时问题,这只是构建动态应用程序的副作用。除此之外,如果你能够编译它,它也会成功运行,但是结果不一定正确。
第二个是异步。Rust 社区的人们喜欢在异步 Rust 上吐槽。这些人一部分来自 NodeJS,其中异步开发被大量嵌入,我似乎无法理解这种“仇恨”。当然,异步 Rust 并不像 NodeJS 那样成熟。有不同的宏可以创建异步特征,但总的来说,我发现异步 Rust 很好。我还没有机会调试异步代码,这可能会很痛苦。如果需要,我们始终可以选择生成线程。
第三个是类型安全。噢,亲爱的上帝!这是真正的类型安全!这感觉非常不可思议。你不再需要寻找 UUID 字符串中可能具有非 uuid 值的愚蠢错误。Rust提供了一个真正的、成熟的类型系统,这是对我们开发工具箱的有效补充。
话虽如此,Rust并非全都是彩虹和巧克力。
坏处
Rust 是一门复杂的语言。我还远没有理解它的所有功能。所以搞得如此复杂,也带来了缺点。
它有一个借用检查器。对于新 Rustaceans 来说,最大的困难之一是借用检查器。简而言之,借用检查器是一种 Rust 机制,是其安全性的核心。这就是防止 Rust 泄漏内存或引用空指针的原因。
了解借用检查器是一件复杂的事情。如果你了解诸如传递引用、传递值、指针以及变量何时超出范围等概念,那么这对于理解借用检查器会有很大帮助。
除此之外,就可以顺利通关,除非有复杂的数据结构来保存对其他类型/对象的引用,大多数Rust代码看起来和读起来都像其他语言一样。
第二个Rust学习或者说入门很艰难。虽然axum与你喜欢的 Web 框架(例如 RoR、fastify或)非常相似,比如django也确实具有独特的功能。像请求提取器这样的中间件工作方式就是错误处理,这些会损害开发者体验以及交付速度。
我之前玩过一个项目很像axum,但我也得承认,使用 NodeJS 可以更快地完成该项目。这可能是我对 NodeJS 有较多的经验有关,也可能是 Rust 开发的一个警告。到那个时候,我已经无法可靠地回答这个问题了。
第三,编译时间。在我的本地机器上,编译速度相对较快。然而,当我切换到 CI/CD 管道时,我却碰到了相对较长的编译时间,约 650 秒(超过 10 分钟)的初始编译时间。
后来我删除多阶段 docker 构建,转而在 CI docker 内编译代码并缓存依赖项后,我能够将编译时间减少到大约 3 分钟。截至今天,整个 CI/CD 管道从推送到部署大约需要 6 分钟,总体来说还不错。
第四,生态系统。Rust 周围有一个非常大的社区和一个很棒的生态系统。社区维护着一堆arewe__yet网站,例如arewewebyet,其中列出了特定区域(在本例中为 Web 开发)的所有流行软件包。
话虽如此,Rust生态系统并不像 NodeJS 或 Python 那么大。许多半流行的软件包和库在这里还找不到。大多数示例将使用 JavaScript、Python、Ruby,甚至 PHP 也提供,但在 Rust 里没有。
你将遇到的许多问题,还有社区中大部分未解答的Rust 问题;在许多情况下,我们必须阅读特定包的源代码才能了解它的工作原理。
不过,我喜欢 Rust 社区的一件了不起的事情是,大多数包都经过测试,这是一个很好的示例。几乎每个流行的包都在存储库中,还附带一个examples文件夹,你可以在其中查看流行的用例,并在它们之上进行构建(例如axum)。