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