本文最初发布于 serokell.io 网站,经网站授权由 InfoQ 中文站翻译并分享。
Rust 已经席卷了编程语言世界。自 2015 年发布 1.0 版以来,它一直是最受欢迎的编程语言之一,且赢得了众多忠实的开发人员和贡献者。
为什么那么多开发者喜欢 Rust?本文试图回答这个问题。我们采访了 1Password 工程副总裁 Michael Fey。
问题 1:能否介绍一下你所在的公司和担任的角色?
答:1Password 是一个密码管理器,获得数百万用户和 70000 家企业的信任,被用来保护他们的敏感数据。它会记住你所有的密码,这样你就不用费劲记下它们了。它提供了适用于所有主要浏览器、桌面和移动设备的应用。
我是 1Password 客户端应用工程副总裁。如果你在 Mac、Windows PC、iPhone、iPad、Android 手机或平板电脑,或在浏览器中使用 1Password,那么你使用的就是我们团队开发的产品。我们的故事从 2004 年一直延续至今,我们为构建精心设计的体验并确保人们的线上安全性而感到自豪。
问题 2:能谈谈 1Password 的技术栈吗?你们代码库有多少是用 Rust 编写的?
答:过去几年,我们一直在 1Password 的生产环境中使用 Rust。我们的 Windows 团队是这项工作的先行者,现在的 Windows 版 1Password 7 大约 70%的代码是用 Rust 编写的。我们还在 2019 年底将 1Password Brain(驱动我们浏览器填充逻辑的引擎)从 Go 移植到 Rust,这样我们就能在我们的浏览器扩展中利用将 Rust 部署到 WebAssembly 的速度和性能优势。
这些代码已经投入生产环境有几年时间,我们取得巨大成功。工作非常顺利,所以我们现在几乎完全重写了整个产品阵容,而 Rust 是这个故事中的关键部分。我们正使用 Rust 创建一个无头的 1Password 应用,其中包含所有业务逻辑、加密、数据库访问、服务器通信,以及包装在我们的目标部署系统的一个原生 UI 层中的更多内容。
问题 3:将 Rust 用于 1Password 的决策是否考虑到 Rust 的优势?
答:最初吸引我们进入 Rust 世界的主要因素之一是内存安全性;得知 Rust 可以帮助我们尽可能提高对客户敏感信息安全性的信心后,我们当然感到非常兴奋。
除了内存安全性外,Rust 生态系统还有很多打动我们的优点。因为 Rust 没有传统的运行时,因此性能有了显著提升。例如,我们不必担心垃圾收集器的开销。Rust 提供了一种“程序正确性”的形式,并提供了许多在运行时避免未定义行为的保证。它的强类型系统在编译时强制执行这些规则。只要精心在应用程序逻辑中融合 Rust 的强类型规则,API 就很难被误用,代码也能得到简化,因为代码无需在运行时检查约束和不变项;Rust 的编译器可以在程序执行前确保其没有无效的运行时代码路径,让你的程序不会误入歧途。需要做的运行时状态验证变少了,于是我们就可以生成更简洁、更高效、更专注和更高质量的代码。与其他语言相比,Rust 需要的运行时调试很少。如果代码可以编译,开发人员就可以肯定它不会表现出意外的行为。它可能不是你想要的,但会是“正确的”。
Rust 另一个非常强大(却经常被忽略)的特性是它的宏流程系统,它让我们能够编写一种工具,可以自动与客户端语言(Swift、Kotlin 和 TypeScript)共享 Rust 中定义的类型。该工具的输出会自动处理序列化/反序列化过程,这意味着我们的客户端开发人员在与 Rust 库交互时可以继续使用他们选择的语言工作,并且避免了通过外部函数接口(FFI)解析 JSON 的麻烦。我们获得了所有这些优势,同时享受了在我们每一种目标语言中做编译时类型检查的好处。我们也已将这款工具集成到我们的持续集成服务器中,这意味着对 Rust 模型的更改可能会导致客户端应用程序的编译失败,而这种失败会在我们的审核流程中被捕获。
该工具已成为我们开发流程中不可或缺的组成部分,让我们获得前所未有的前进速度。一旦我们在 Rust 中定义了类型,就可以立即用客户端语言生成等效的类型。这让我们的开发人员可以专注于解决问题,而无需手动编写样板代码以通过 FFI 通信。
问题 4:在开发 1Password 这样以安全为中心的应用程序时,Rust 提供的支持(库和其他方面)有多好?
答:Rust 生态有足够的能力来建立以安全为中心的应用程序所需的大部分基础。有两个大型的顶尖加密平台(ring和Rust Cryptogroup),它们共同提供了丰富的功能选项。正如我上面提到的,使用 Rust 编写代码本身就可以让你对内存使用有更多信心,并且减少了向应用程序中意外引入与内存相关漏洞的几率。还有一个完善的系统可以跟踪不时出现在 Rust 板条箱中的漏洞:RustSec数据库,该数据库由其他 Rust 开发人员在社区提供,并经常更新一些可在 CI 审核扫描中使用的新信息。Rust 和 Cargo 还带有功能丰富的测试框架,为开发人员提供了一种简便的方法来编写单元测试套件,以确保关键代码(例如你编写的各种加密函数)的行为正确。
尽管支持所有功能的安全的原生 Rust 库还是一个梦想(它们迟早会成为现实),但总有一种选项可以轻松地使用 C 或原生平台库中的某些东西。我们将其用于 Rust 代码中,以高效实现诸如调用生物识别解锁的原生实现(Touch ID、Face ID、Windows Hello)以及平台特定的设置实现(例如苹果平台上的 NSUserDefaults)之类的功能。
问题 5:有哪些 Rust 库是你特别推荐的?
答:Tokio、Hyper/Reqwest、Ring 和 Neon 都在 1Password 中拥有一席之地,它们对于这个雄心勃勃的项目而言至关重要。你还应该在 crates.io 上查看我们的password-rules-parser,它基于一套主要由苹果支持的规范。它们的工具和文档可以在这里找到。
问题 6:Rust 用起来有哪些明显的优势,在你们的技术栈中有哪些不足?
答:当我们开始这个项目时,Rust 已经实现了我们期望的 90%。我们已经能以某种形式将其部署到几乎每个目标平台上(Apple Watch 除外)。这种语言本身的设计颇具现代感,并且每次更新发布时都在不断改进。它有着出色的文档资料和活跃的社区。
尽管有无数可用的板条箱,但我们确实需要推出自己的日志记录和跟踪工具,以确保它们在 1Password 中可以安全使用。此外,我们构建了一个实质上本地化的实现,以满足我们产品的需求。
它确实在一个关键方面无法满足我们的要求:我们希望 WebAssembly 在浏览器和浏览器扩展方面能提供比现在更强大的能力。WebAssembly 作为一个函数库来说非常出色,但尝试在 WASM 中支持整个运行时一直是一个挑战。但我们遇到的许多问题并不是 Rust 本身的局限,而是 WebAssembly 作为部署平台存在的局限。
问题 7:用 Rust 开发 1Password 时遇到的最大挑战是什么?
答:我们团队中的许多人都是 Rust 新手,他们经历了内存管理和所有权模型的典型学习曲线。我们还发现编译时间比较漫长,我们的 CPU 和风扇经受了不小的考验。
问题 8:你们对结果感到满意吗?
答:毫无疑问是满意的。
问题 9:有哪些重要的收获?
答:如果你不熟悉 Rust,请从小处入手,并以此为基础逐渐推进。当我们开始尝试探索基于 Rust 的解决方案所能提供的优势时,我们做了大量实验。当你的实验顺利进行时,请尝试重新思考一下你以前使用其他语言时的工作方式,看一看你的代码是否可以从 Rust 的理念中受益。
原文链接:
https://serokell.io/blog/rust-in-production-1password?fileGuid=RwXKW63W3XhC3WcC
评论