使用 Rust 来解决 CPU 性能产生的 npm 软件包注册瓶颈前端
事实与数据:android
共有超过 836,000 个 JavaScript 包可用
每月使用 npm 下载的软件包超过三百亿
下载来自于超过一千万个用户
复制代码
npm 公司(npm, Inc.)是 npmjs.com 网站和 npm 注册服务背后的公司。它是全世界最大的软件注册中心,天天有高达 13 亿的包下载量。除了维护开源软件包注册,npm 公司也提供企业级的软件包注册产品,并维护着一个用于与注册信息交互的命令行工具。ios
npm 所面临的挑战是对效率和扩展性的要求。若是服务部署后能够被遗忘(译注:指服务不须要花精力维护),咱们就节约了宝贵的时间,能够处理别的问题。npm 员工们也很但愿,他们所使用的技术有一个有帮助的社区。Rust 符合这些要求,并且在 npm 目前的技术栈中也有部分使用。git
npm 工程团队时刻关注着随着 npm 包指数增加可能致使的性能问题。大多数状况下 npm 的操做性能受限于网络,JavaScript 足以支撑实现性能目标。然而,决定用户是否被容许发布软件包的认证服务,是一个受限于 CPU 性能的任务,预计会成为性能瓶颈。github
Node.js 中使用传统 JavaScript 实现的这个服务不管如何都须要重写,因此 npm 团队借此契机,考虑在服务降级前从新实现,既使得代码更现代化,又能提升服务性能。npm
当考虑替代技术时,npm 团队很快否决了 C,C++和 Java 实现,而密切关注 Go 语言和 Rust 语言。编程
在 npm 工程团队的考虑中,C 或 C++ 解决方案再也不是一个合理的选择。“我不相信本身能写一个 C++ HTTP 应用程序,而后把它发布到网络上,”npm 的工程师 Chris Dickinson 解释说。这些语言须要内存管理方面的专业知识,以免可能致使灾难性问题的错误。即便是为了提升性能,npm 公司也没法容忍安全问题、系统崩溃和内存泄漏的发生。后端
Java 也未被考虑,由于要部署任何程序到生产服务器上,都得带上 JVM(Java 虚拟机)和相关类库。这是一系列复杂操做,会产生资源消耗,与 C 或 C++的不安全性同样难以接受。安全
考虑到这些要求,所选的编程语言应该:bash
所以最后考虑使用的是 Go 语言和 Rust 语言。
为了评估候选方案,npm 团队分别使用 Node.js、Go 语言和 Rust 语言重写了受权服务。
使用 Node.js 重写的服务被当作基准线,以评估使用 Go 语言和 Rust 语言带来的变化。如你所料,npm 有不少 JavaScript 专家。使用 Node.js 重写受权服务大约用了一个小时,性能表现与过去实现的差很少。
使用 Go 语言重写受权服务用了 2 天。在这个过程当中,npm 团队对于缺乏依赖管理的解决方案感到失望。npm 公司致力于让 JavaScript 依赖管理可预测,而且用起来绝不费力,他们期待其余语言生态也有一样的世界级依赖管理工具。Go 语言的依赖安装全球化进程、跨项目版本共享的前景(在他们进行评估时 Go 语言的标准)都不具备吸引力。
当开始用 Rust 语言实现时,他们在依赖管理方面发现了鲜明的对比。“Rust 语言有着绝对使人惊叹的依赖管理,”一位工程师热情地说,他指出 Rust 的依赖管理策略从 npm 得到了灵感。Rust 语言安装时附带的 Cargo 命令行工具与 npm 命令行工具相似:Cargo 分开协调每个项目中的各依赖版本,从而让搭建每一个项目时所在环境不会影响最终的执行结果。Rust 语言的开发体验很友好,符合 npm 团队受到 JavaScript 影响的预期。
Rust 语言有着绝对使人惊叹的依赖管理。
使用 Rust 语言重写受权服务的时间其实比 JavaScript 版本和 Go 语言版本的都长:大约用了一周来熟悉语言并进行实现。Rust 感受像是一种更难以搞定的编程语言。语言的设计预先加载了不一样于其余常见编程语言的内存使用决策,以确保内存安全性。“你能够写出一个正确的程序,可是你必须考虑到这个程序的方方面面,”Dickinson 说。然而,当工程师们遇到问题时,Rust 社区友善地回答了问题,颇有帮助。这一点让 npm 团队可以用 Rust 语言重写服务并将其部署到生成环境。
我对 Rust 最大的恭维就是它很“无聊”。
npm 的第一个 Rust 程序在一年半的生产使用中没有引发任何警报。“我对 Rust 最大的恭维就是它很‘无聊’,”Dickinson 说,“而这是一个很棒的恭维。”部署新的 Rust 服务的过程很简单,很快他们就忘记了这个 Rust 服务,由于它极少引发运行问题。在 npm 公司,将 JavaScript 服务部署到生产环境的通常经验是,要对服务的错误和过多的资源占用进行大量监控,从而须要调试和重启。
npm 称 Rust 社区是决策过程当中的一个积极因素。他们认为 Rust 社区颇有价值的一些方面是他们的包容、友好以及作出困难的技术决策的可靠流程。这些方面使 Rust 语言的学习和解决方案的开发更容易,并保证了语言将以健康、可持续的方式继续提升。
每一个技术决策都须要权衡利弊,将 Rust 语言加入 npm 的生产服务也不例外。将 Rust 引入 npm 的最大缺点是,现有的 JavaScript 技术栈和新的 Rust 技术栈都有本身的解决方案,用来进行状态监视、日志记录与发出警报;而维护这些解决方案有必定的负担。做为一门年轻的语言,Rust 尚未用以完成工业级产品标准的库和最佳实践,可是但愿在不久的未来能实现。
Rust 语言是一种可扩展且易于部署的解决方案。它能够占用较少的资源而不影响内存安全性。经过 Cargo 的依赖管理为系统编程领域带来了现代化工具。虽然仍有最佳实践和工具备待提升,但社区的创建保证了长期成功。出于这些缘由,npm 选择了 Rust 来处理 CPU 限制的性能瓶颈。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。