-
您(nín)的位置:
- 网站首页
- > 新(xīn)闻(wén)资(zī)讯
- > 技术(shù)前沿
您(nín)的位置:
Rust 是一门神奇的(de)编程(chéng)语言,有非常好的 CLI 工具,比如 ripgrep 和 exa。像 Cloudflare 这样的公司(sī)正在使用并 鼓励人们(men)写 Rust 来运行微服务。Rust 编写的软(ruǎn)件可(kě)能比 C++ 或 C 更安全、更小、更简洁。
如(rú)果我正(zhèng)在编写一个地理编码器、一个路由引擎、一个实时消息(xī)平台、一个数据(jù)库或一个(gè) CLI 工具,Rust 最合适。
但去年,我试图用 Rust 写一个传统网站的纯 API 服务,Rust 就不(bú)合适(shì)了。
Rust 有大量(liàng)的 Web 服务(wù)框(kuàng)架、数据(jù)库(kù)连接器和解析器。但(dàn)搭建身份(fèn)验证服务方面(miàn)只有非常低层次的组(zǔ)件。Node.js 有 passport.js,Rails 有 devise,Django 有(yǒu) 开(kāi)箱(xiāng)即(jí)用的身份验证模型,在(zài) Rust 中,你需要学习如(rú)何将共享 Vec 转换到底层加密库才能构建这个系统。
译(yì)者注,Vec 是(shì)一个动态数组,只会自动(dòng)增长而不会(huì)自动收(shōu)缩。区别于 Array,Vec 具有动态(tài)的添加和删除元素的能力,并且能够(gòu)以 O(1) 的效率进行随机访问。Vec 的所有内容项都是生(shēng)成在堆空间上(shàng)的(de),可(kě)以轻易的将(jiāng) Vec 移出一个栈而不用担(dān)心内存拷(kǎo)贝影响(xiǎng)执行效率,毕竟只(zhī)是(shì)拷贝栈上的(de)指(zhǐ)针。
有些(xiē)库试图(tú)解决这个问题(tí),比如 libreauth,但它才(cái)刚(gāng)刚开始开发。还有很(hěn)多类似的 Web 框架问题(tí)。
SDK 呢?在主流编程(chéng)语言(yán)中,你可(kě)以通过(guò)一个官方(fāng)库(kù)来接入 Google 云服(fú)务、AWS 或 Stripe。这些官方库大都很棒。例(lì)如(rú),aws-sdk-js 和 Stripe 库的设计和维护得非(fēi)常好。
Rust 就不这样,只有少许(xǔ)第三方库(kù),但以这些服务(wù)的(de)开发速度,它们真的能够提(tí)供(gòng)高质(zhì)量的(de)体(tǐ)验吗(ma)?
有人会(huì)说好吧,X 编程语言太好(hǎo)了,你可以在周末自己写一个 SDK!我必须回答,不。
Rust 的生态系统在其(qí)它领域非常丰富(fù)。用于构建 CLI、管理并发性、使用二进(jìn)制数(shù)据(jù)和底层解析器的 crates 令人印象深刻(kè),非常棒。
我一直在(zài)看 Nicholas Nethercote 的博(bó)客,描(miáo)述了(le) Rust 团队如何优化编译(yì)器(qì),让它更快!
但与其(qí)它编程语言相比,用它构建(jiàn)网(wǎng)站会很慢。它比(bǐ)编译型编程语言 Go 慢(màn)得(dé)多,也比解释型编程语言(yán) JavaScript、Ruby 和(hé) Python 等慢得(dé)多。
一旦(dàn)代码被编译,一(yī)切就变得非常棒了!但(dàn)在(zài)我的情况下,甚至基本 API 功能都不完整,一(yī)个不复杂的系统——居(jū)然花了 10 多分钟来编(biān)译。Google 代码构建 的(de)硬(yìng)件配置很差,每次(cì)都会超时(shí),我(wǒ)啥都编译不了。
只要(yào)不重建(jiàn)缓存依(yī)赖项,缓存就有(yǒu)意(yì)义。也(yě)许 减(jiǎn)少(shǎo)依赖 会加(jiā)快 Rust 项(xiàng)目编(biān)译(yì)。但就像(xiàng) serde,几乎(hū)所有人(rén)都使用的 JSON 和其它序(xù)列化 / 反序列化(huà)程序占用了大量的编译(yì)时间。我们是否应该用编译速度更(gèng)快但缺乏大量(liàng)文档(dàng)和生态系统支持(chí)的东西来取(qǔ)代 serde?这种取舍非常糟糕(gāo)。
Rust 让你从代(dài)码维度进(jìn)行思考,这对系统编程来说非常重要。它让你思考如何共享或复制内存,思考真(zhēn)实但(dàn)不太可(kě)能(néng)的(de)小概率事件,并确保妥善处理(lǐ)它们,帮你编(biān)写(xiě)各种各样的高效代码。
这些担(dān)忧(yōu)都是(shì)合(hé)理的,但是对于大多数 Web 应用程序来说,它们并不是最重要的关注点(diǎn),以流(liú)行的(de)惯性思考会导(dǎo)致不正确的假设。
就拿 Rust 的(de)安全性来说吧。这是(shì)它宣传语中的重要(yào)部分,这是绝对(duì)正确的:Rust 的承(chéng)诺安(ān)全和底层两者兼而(ér)有之——它可以在没有垃圾收(shōu)集器的情况下(xià)工作(zuò),同时防止基于内存的漏洞。当你读到“安全”的时候,想想 Rust 的竞(jìng)争对手 C 吧(ba)。C 语言中的代(dài)码可以引用任意内存,很容(róng)易溢出和出错。Rust 代码(mǎ)可以和 C 代(dài)码一样(yàng)快,但是可以保护内存访(fǎng)问,而不(bú)需(xū)要(yào)垃圾(jī)收集器或某种运行时检查。
但是 Rust 的内存规则并不比 Node.js 或 Python 更安全,用 Rust 编(biān)写的 Web 应用程序在(zài)系统上不(bú)会比 Python 或 Ruby 应用程(chéng)序安全(quán)。带有垃圾收(shōu)集器的高级编程(chéng)语言通常为避免这类漏洞利用(yòng)和错(cuò)误而付出性能损失(shī)。不能在(zài) JavaScript 中引用(yòng)未(wèi)初(chū)始化的内存,因(yīn)为 JavaScript 中不(bú)进行(háng)内存间的引用。
旁(páng)注:这(zhè)是在描述 Node.js 和其它系统的设计目(mù)标——它们确实偶尔(ěr)会(huì)有 bug。Node.js 的缓存对象,就值得读(dú)一读。
你要是 问一些人,他(tā)们(men)会说(shuō)如果使用不安全的(de)代码,Rust 相比带有内(nèi)存回收的编程语言是不安全的——包括最流行的 Web 框架 Actix(译者注,Actix 是 Rust 的 Actor 异步并发框架,基于 Tokio 和 Future,开箱具有异步非阻塞(sāi)事件驱动并发能力,其实现低层级 Actor 模型来提供无锁(suǒ)并发模型(xíng),而且同时提(tí)供同步 Actor,具有快速(sù)、可靠,易可扩(kuò)展 https://actix.rs/),因为 不安全代码(mǎ)允(yǔn)许原始指(zhǐ)针(zhēn)的延迟(chí)。
如果你正(zhèng)在写一个(gè)视频游戏(xì),暂停执(zhí)行(háng)垃圾(jī)收集是不好的。如果你在编写微控制器代码(mǎ),任何内存(cún)“开销”或浪费都是非常糟糕的(de)。但是大多数 Web 应用程序可以节省一点内存开销(xiāo)来(lái)换(huàn)取生产性(xìng)能(néng)。
Rust 的其它属性(xìng)面对(duì)的争议几乎一样(yàng)。它的并发(fā)特(tè)性是太神奇了,如果你在做一些复(fù)杂的事(shì)情,需要快速响应,这当然(rán)很棒。但如(rú)果情况不(bú)是(shì)这样呢?至少可以(yǐ)说,Rust 的异步生态系统面临着(zhe)很大挑战:各种不相关(guān)的(de)领(lǐng)域(yù)中有着不同(tóng)的异步(bù)实现,比如 tokio。
相(xiàng)比较之下,Python 的 Tornado 和 Twisted 异(yì)步实(shí)现的很奇怪,Node.js 异步(bù)实现的很(hěn)好,但语法都很丑陋。
我确(què)信,Rust 的(de)异步将会稳定和统一(yī),未来会更容易操作,但(dàn)我(wǒ)现(xiàn)在就要用啊。
很多(duō)人正在学 Rust,用 Rust 编写 CLI 应用程序或底层代码,并且玩(wán)得非常开心。使用 Rust 编写普通 Web 应用(yòng)程序的人明显少很(hěn)多。
这是技术选择中的重(chóng)要(yào)部分:是(shì)否(fǒu)有(yǒu)人在使用该工(gōng)具?他(tā)们(men)大致在同一个(gè)领域吗?不幸的是,Rust 生态系统中许多令人难以置信的令(lìng)人兴奋的工作与 Web 应用服务(wù)器无关。的(de)确存在一些很(hěn)有前途的 Web 框架——甚至更高层(céng)次的框架,但毫无(wú)疑问(wèn),它们市(shì)场很小。即使(shǐ)是主(zhǔ)要的 Web 框(kuàng)架 Actix 也只(zhī)有几(jǐ)个顶尖贡献者。
如果 Rust 以目前的速度增长(zhǎng),那么社区中(zhōng)的 Web 部分将达到一个临界(jiè)值,但我认为没(méi)有足(zú)够多的人(rén)使用 Rust 作为(wéi)网站的实用工具。与其它社区(qū)相(xiàng)比(bǐ),有很多公(gōng)司致力于使用现有的工具来构建 Web 应用程序,这些工具不是最(zuì)前沿的,但足(zú)够将成熟技(jì)术与新技(jì)术区分开(kāi)来。
这一部分不仅仅(jǐn)是 Rust,它(tā)还涉及(jí) GraphQL 生态系统,Rust 参与这个生态系统就是一个(gè)例(lì)子。
N+1 问题 是(shì)每(měi)个构(gòu)建 Web 应用程序(xù)的人都应该知道的。要(yào)点是:你有一(yī)页照片(一次查询),你要显示每张照(zhào)片的作(zuò)者(zhě),会有多少次查询:1,合并照片和作者,或者在(zài)检索照(zhào)片后对每(měi)张(zhāng)照片进行查询(xún)以获(huò)取作者?或者两次,第二次(cì)查询 ids 中(zhōng)的 user.id,一次获取所有作者,然后重(chóng)新设置他(tā)们的(de)照片属性。
N+1 查询通常优先使用(yòng)数(shù)据库解决:比如将 N+1 查询(xún)改为单个(gè)查询,会带来(lái)明显的(de)性能优化(huà)。我们有很多方法来尝试和解决这些问题:你可以(yǐ)编写 SQL,并尝试使用 CTE 和 JOIN 在单(dān)个查询中(zhōng)完成大量工作,就像我们在 Observable 中所做的(de)那样,或者使(shǐ)用(yòng)像(xiàng) ActiveRecord 这(zhè)样的 ORM 层将 N+1 查(chá)询转(zhuǎn)换为可(kě)预测查询的快速方法。
Juniper 是一个用于(yú) Rust 应用(yòng)程序的 GraphQL 服务。GraphQL 基本上都是由前端应用程(chéng)序定(dìng)义(yì)查询(xún),而(ér)不是后端。给它一系列可以查询的东西,然后应(yīng)用程序(React 或其它)将任意查询发送到(dào)后端。
这会让(ràng)后端变得复杂。任(rèn)何 SQL 级别的(de)优化都不可(kě)能做到——你的(de)服(fú)务器正(zhèng)在编写动(dòng)态 SQL,优化只能依赖(lài) GraphQL 服(fú)务(wù),但它不会总是有效。例如:Juniper 默认情况下执(zhí)行的是 N+1 查(chá)询,解(jiě)决方案 dataloader 还比较粗糙且需要单(dān)独维护(hù)。因此,最终您将拥有一个非常(cháng)快(kuài)的应用(yòng)程序层,但它所有的时间都花在了(le)极其(qí)低效的数据库查询(xún)上。
总之,GraphQL 与 NoSQL 数据(jù)库配(pèi)合使用效果非常好,它可以快速为这些类型的请求提供服(fú)务。我确信 Facebook 内部(bù)有一(yī)些特定的数据库与(yǔ) GraphQL 结合在一(yī)起使用效果非常棒(bàng),但(dàn)业内其他(tā)企业则非(fēi)常依赖(lài) Postgres 和同(tóng)类产品。
首(shǒu)先,本文提到的(de)问题并不(bú)针对在通用场景使用 Rust,只(zhī)针对(duì)将 Rust 用(yòng)于特定目标和生(shēng)态系统,简单说就是(shì) Web API。
注意事项 1:一般情况下,你可以用任何编程(chéng)语言搭建网站,还记得基(jī)于 C++ 实现的OkCupid 吗?(译者注,OkCupid 是(shì)美国一个大型(xíng)线上交友网站)还有一(yī)个非常流(liú)行的 星象应(yīng)用程序,Co-star,它全部是用 Haskell 编写(xiě)的。如(rú)果(guǒ)你(nǐ)擅长其它编程(chéng)语言,或者可以招(zhāo)聘到擅长这些编程语言的工程师,你一样可(kě)以取得(dé)成功。
注意事项(xiàng) 2:我试图构建(jiàn)的(de)是重 CRUD(增删改(gǎi)查) 的 Web 应用(yòng)程序 API。它可能不(bú)算是一个 Web“服务”——主要(yào)是快速(sù)、无数次地执行同一个操作,而是(shì)一个 Web“应用程序”——执行了许多不同的操(cāo)作,包(bāo)含了相当多的业务逻辑。如果你要(yào)开发的东西跟我在做(zuò)的不一样,那我(wǒ)的建议可(kě)能就不适合你。如果你需(xū)要的是快速执行一两个操作,比如你(nǐ)正(zhèng)在(zài)写一个支付网关(guān)或语音消息应用程序(xù),那 Rust 可能(néng)效果还是(shì)不错(cuò)的。
注(zhù)意事项(xiàng) 3:这篇(piān)文章写于 2021 年 1 月(yuè),如(rú)果接下(xià)来社区继续(xù)发展(zhǎn),Rust 将得(dé)到持续的改(gǎi)进(jìn),会变得更好并更易于 Web 应用程序开发。
总而言之,我真(zhēn)的很喜欢使用 Rust,这是一门美丽的(de)编程语言,有很多很酷(kù)的想(xiǎng)法。希(xī)望很快,Rust 会成为能(néng)用来构建我想做的东西的最合(hé)适的工具。不过(guò),现(xiàn)在(zài)我想做(zuò)的很多东西都要采(cǎi)用不同(tóng)特(tè)性的编程语(yǔ)言才能更好地运行。
https://macwright.com/2021/01/15/rust.html