Rust是制作Web API的困难方法

2021-01-16 08:20:50

Rust是一种很棒的语言。它启用了出色的CLI工具,例如ripgrep和exa。诸如Cloudflare之类的公司正在将Rust用于其自己的系统,并鼓励人们编写Rust以运行微服务。借助Rust,可以编写出比C ++或C更安全,更微型,更简洁的真正快速的软件。

如果我正在编写地理编码器,路由引擎,实时消息传递平台,数据库或CLI工具,Rust将位于列表的顶部。

但是去年,我花了一些时间试图使Rust在普通的API上工作,以为普通网站提供支持。这不是一个很好的选择。

Rust具有相当数量的Web服务器框架,数据库连接器和解析器。但是建立身份验证?您只有非常低级的部分。 Node.js将为您提供护照,Rails进行了设计,而Django为您提供了一个现成的auth模型,在Rust中,您将通过学习如何将共享的vec传递到低级加密库中来构建该系统。有一些库试图解决此问题,例如libreauth,但是它们是新生事物,并且是利基市场。对其他许多Web框架问题重复上述步骤。

SDK怎么样?使用主流语言,您可以通过引入官方库来插入Google Cloud Services,AWS或Stripe。这些库大多很棒。例如,aws-sdk-js和Stripe库经过精心设计和维护。

Rust并非如此。有一些第三方库试图填补空白,这很棒,但是由于这些服务的飞速发展,他们真的能够提供优质的体验吗?

有人会说,X语言很棒,您可以在周末自己编写一个SDK!我必须回答,不。

Rust的生态系统在其他领域也很丰富。用于创建CLI,管理并发性,使用二进制数据和低级解析器进行令人印象深刻的操作的板条箱非常出色。

多年来,我一直在阅读Nicholas Nethercote的优秀博客,其中他描述了Rust团队如何使编译器更快。而且他们当然使它变得更快!

但是,与您用来建立网站的其他语言相比,它的速度很慢。它比Go编译器要慢得多,比JavaScript,Ruby和Python等解释型语言的启动时间要慢得多。

编译代码后,一切都将变得非常棒!但就我而言,这个基本的API(甚至还没有功能完善而且绝不是一个复杂的系统)需要十多分钟的时间来编译。在Google Code Build较弱的硬件上,每次都会用完时间。我们什么都做不了。

只要您不必重建缓存的依赖项,缓存就会有所帮助。而且,我不知道,也许减少依赖关系将有助于Rust项目更快地编译。但是例如serde(几乎每个人都使用的JSON和其他格式的序列化器/反序列化器)占用了大量的编译时间。我们是否应该使用编译速度更快但缺乏强大文档和生态系统支持的产品来代替serde?这是一笔不好的交易。

Rust使您考虑对系统编程至关重要的代码尺寸。它使您考虑如何共享或复制内存。它可以让您考虑真实但不太可能发生的极端情况,并确保已对它们进行处理。它可以帮助您以各种可能的方式编写出令人难以置信的高效代码。

这些都是有效的担忧。但是对于大多数Web应用程序而言,它们并不是最重要的问题。而围绕流行语的思考会导致一些错误的假设。

以Rust的安全为例。这是市场营销的重要组成部分,而且绝对正确:Rust的主要承诺是安全且低级别-它无需垃圾收集器即可工作,同时还能防止基于内存的漏洞。当您阅读“安全性”时,请考虑Rust与C竞争。C中的代码可以引用任意内存,可以轻松地溢出和段错误。 Rust代码可以与C代码一样快,但是可以保护该内存访问,而无需花费垃圾回收器或某种运行时检查的费用。

但是Rust的内存规则并不比Node.js或Python的安全。用Rust编写的Web应用程序在系统上不会比使用Python或Ruby的应用程序更加安全。带有垃圾回收器的高级语言通常会回避整个漏洞利用和漏洞,以换取性能损失。您无法在JavaScript中引用未初始化的内存,因为您根本无法在JavaScript中引用作为内存的内存。

这是在描述Node.js和其他系统的设计目标-他们偶尔确实会出现一些漏洞,这些漏洞会潜入这个问题区域。例如,可以很好地了解Node.js的Buffer对象的先前行为。哎呀,如果您问一些人,如果您使用任何带有不安全代码的板条箱(包括最流行的Web框架Actix),Rust的安全性就不如GC应用程序的Web应用程序语言,因为不安全的代码允许诸如延迟原始指针之类的操作。

如果您正在编写视频游戏,则暂停运行垃圾回收很不好。如果您正在为微控制器编写代码,那么任何内存“开销”或浪费都是非常糟糕的。但是大多数Web应用程序可以节省一点内存开销,以换取生产力。

对于Rust的其他属性,此参数几乎相同。如果您要执行复杂的操作并且需要快速的性能,那么它的并发原语非常棒。但是,如果不是?至少可以说,Rust异步生态系统具有挑战性:存在各种类型的异步项目,这些项目跨越域来对不相关的东西(例如tokio)进行异步实现。

与Python.Tornado或Twisted(它们有一个怪异的异步故事,也有丑陋的语法)相比,它感觉上不像Node.js(它有一个很好的异步故事,但语法很丑)。

我敢肯定,异步将稳定和均匀化,并且将来会更容易实现。但是我现在正在工作。

当前有很多人学习Rust,用Rust编写CLI应用程序或低级代码,并度过了一个非常愉快的时光。使用Rust编写普通的Web应用程序的人数大大减少。

这是技术选择方程式的重要组成部分:是否有人在使用该工具,并且他们大致在同一领域吗?不幸的是,Rust生态系统中许多令人难以置信的激动人心的工作与Web应用程序服务器无关。有一些有前途的Web框架-甚至是更高级别的框架-无疑是利基市场。甚至主要的Web框架Actix也有大量的贡献者。

如果Rust的发展速度如此之快,社区的网络部分将达到某种临界水平,但是对-我认为没有足够的人将Rust用作网站,使其成为实用的网站工具。并与其他社区进行比较,在该社区中,整个公司都致力于使用现有工具来构建Web应用程序-不是尖端工作,而是将成熟技术与新技术区分开的那种东西。

这部分不仅涉及Rust,还涉及GraphQL生态系统,Rust参与该生态系统就是一个例子。

n + 1问题是每个构建Web应用程序的人都应该理解的问题。要点是:您有一张照片页面(1个查询)。您想显示每张照片的作者。您最终要进行多少次查询:1,合并照片&作者,或查询每张照片以检索照片后获得作者?或2个查询,第二个查询具有诸如user.id IN ID之类的内容,可一次性获取所有作者,然后将其重新连接到他们的照片。

n + 1查询通常是优先级最高的数据库修复程序:它们通常具有很高的影响力,并且将n + 1查询更改为单个查询通常是一个大胜利。我们有很多方法来尝试解决它们:您可以编写SQL并尝试使用CTE和JOIN在单个查询中完成很多工作,就像我们在Observable所做的那样,或者使用ActiveRecord之类的ORM层来快速地解决这些问题。将n + 1个查询变成可预测的查询。

我们正在使用Juniper,这是用于Rust应用程序的GraphQL服务器。 GraphQL基本上允许您的前端应用程序定义查询,而不是后端。您给它提供了一系列可以查询的内容,然后应用程序-React或其他东西-将任意查询发送到后端。

这使后端变得困难。任何形式的SQL级优化都是不可能的-您的服务器正在编写动态SQL,因此您依赖于GraphQL服务器的智能,而这种智能并不总是那么高。以Juniper为例,默认情况下为n + 1个查询。解决方法-数据加载器-很粗糙并且需要独立维护。因此,归根结底,您将拥有一个快速增长的应用程序层,该层将花费所有的时间低效地查询数据库。

这个词就是说GraphQL与非SQL数据库可以很好地配合使用,后者可以快速地满足这类请求。我敢肯定,在Facebook内部使用了一些特殊的数据库,将其与GraphQL结合使用令人难以置信,但是,出于充分的原因,其余行业都与Postgres及其同类紧密相关。

因此,我尝试着主要警告:这与Rust无关。这是关于将语言及其生态系统用于特定目标的信息。简单的Web API。

需要注意的是:从一般意义上讲,您可以使用任何内容构建网站并获得成功。请记住,如何在C ++中实现OkCupid。 Haskell就是一个受欢迎的占星术应用,联合明星。如果您擅长编写某种语言,并且可以聘请其他有很多才能的人,那么您可以做到并成为英雄。

另一个警告:我试图构建的是网站的CRUD繁重的Web应用程序API。如今,它已不是一种您可以称呼它的网络“服务”,它一次完成了数百万次的快速操作,但是却成为了一个“应用程序”,它做了许多不同的操作,并且拥有相当多的域名逻辑。如果您不是要构建这种东西,则此建议可能不适用!如果您需要以超快的速度执行一两个操作,例如正在编写付款网关或语音消息传递应用程序,Rust的权衡可能会更好。

这是另一个警告:我将在2021年1月写这篇文章。假设社会继续运转,Rust将会发展并可能会变得更好,并且它对于Web应用程序开发来说真的很容易使用。

所有人都说,我非常喜欢与Rust一起工作。这是一门优美的语言,包含许多很棒的主意,我希望很快我会考虑要构建的东西,而Rust将是正确的工具。但是,就目前而言,具有不同优先级的语言可以更好地满足我想构建的许多东西。