如果我正在編寫一個地理編碼器、一個路由引擎、一個實(shí)時消息平臺、一個數(shù)據(jù)庫或一個 CLI 工具,Rust 最合適。 但去年,我試圖用 Rust 寫一個傳統(tǒng)網(wǎng)站的純 API 服務(wù),Rust 就不合適了。 Rust 有大量的 Web 服務(wù)框架、數(shù)據(jù)庫連接器和解析器。但搭建身份驗(yàn)證服務(wù)方面只有非常低層次的組件。Node.js 有 passport.js,Rails 有 devise,Django 有開箱即用的身份驗(yàn)證模型,在 Rust 中,你需要學(xué)習(xí)如何將共享 Vec 轉(zhuǎn)換到底層加密庫才能構(gòu)建這個系統(tǒng)(譯者注,Vec 是一個動態(tài)數(shù)組,只會自動增長而不會自動收縮。區(qū)別于 Array,Vec 具有動態(tài)的添加和刪除元素的能力,并且能夠以 O(1) 的效率進(jìn)行隨機(jī)訪問。Vec 的所有內(nèi)容項(xiàng)都是生成在堆空間上的,可以輕易的將 Vec 移出一個棧而不用擔(dān)心內(nèi)存拷貝影響執(zhí)行效率,畢竟只是拷貝棧上的指針)。有些庫試圖解決這個問題,比如 libreauth,但它才剛剛開始開發(fā)。還有很多類似的 Web 框架問題。 SDK 呢?在主流編程語言中,你可以通過一個官方庫來接入 Google 云服務(wù)、AWS 或 Stripe。這些官方庫大都很棒。例如,aws-sdk-js 和 Stripe 庫的設(shè)計和維護(hù)得非常好。 Rust 就不這樣,只有少許第三方庫,但以這些服務(wù)的開發(fā)速度,它們真的能夠提供高質(zhì)量的體驗(yàn)嗎? 有人會說好吧,X 編程語言太好了,你可以在周末自己寫一個 SDK!我必須回答,不。 Rust 的生態(tài)系統(tǒng)在其它領(lǐng)域非常豐富。用于構(gòu)建 CLI、管理并發(fā)性、使用二進(jìn)制數(shù)據(jù)和底層解析器的 crates 令人印象深刻,非常棒。 我一直在看 Nicholas Nethercote 的博客,描述了 Rust 團(tuán)隊如何優(yōu)化編譯器,讓它更快! 但與其它編程語言相比,用它構(gòu)建網(wǎng)站會很慢。它比編譯型編程語言 Go 慢得多,也比解釋型編程語言 JavaScript、Ruby 和 Python 等慢得多。 一旦代碼被編譯,一切就變得非常棒了!但在我的情況下,甚至基本 API 功能都不完整,一個不復(fù)雜的系統(tǒng)——居然花了 10 多分鐘來編譯。Google 代碼構(gòu)建的硬件配置很差,每次都會超時,我啥都編譯不了。 只要不重建緩存依賴項(xiàng),緩存就有意義。也許減少依賴會加快 Rust 項(xiàng)目編譯。但就像 serde,幾乎所有人都使用的 JSON 和其它序列化 / 反序列化程序占用了大量的編譯時間。我們是否應(yīng)該用編譯速度更快但缺乏大量文檔和生態(tài)系統(tǒng)支持的東西來取代 serde?這種取舍非常糟糕。 Rust 讓你從代碼維度進(jìn)行思考,這對系統(tǒng)編程來說非常重要。它讓你思考如何共享或復(fù)制內(nèi)存,思考真實(shí)但不太可能的小概率事件,并確保妥善處理它們,幫你編寫各種各樣的高效代碼。 這些擔(dān)憂都是合理的,但是對于大多數(shù) Web 應(yīng)用程序來說,它們并不是最重要的關(guān)注點(diǎn),以流行的慣性思考會導(dǎo)致不正確的假設(shè)。 就拿 Rust 的安全性來說吧。這是它宣傳語中的重要部分,這是絕對正確的:Rust 的承諾安全和底層兩者兼而有之——它可以在沒有垃圾收集器的情況下工作,同時防止基于內(nèi)存的漏洞。當(dāng)你讀到“安全”的時候,想想 Rust 的競爭對手 C 吧。C 語言中的代碼可以引用任意內(nèi)存,很容易溢出和出錯。Rust 代碼可以和 C 代碼一樣快,但是可以保護(hù)內(nèi)存訪問,而不需要垃圾收集器或某種運(yùn)行時檢查。 但是 Rust 的內(nèi)存規(guī)則并不比 Node.js 或 Python 更安全,用 Rust 編寫的 Web 應(yīng)用程序在系統(tǒng)上不會比 Python 或 Ruby 應(yīng)用程序安全。帶有垃圾收集器的高級編程語言通常為避免這類漏洞利用和錯誤而付出性能損失。不能在 JavaScript 中引用未初始化的內(nèi)存,因?yàn)?JavaScript 中不進(jìn)行內(nèi)存間的引用。 旁注:這是在描述 Node.js 和其它系統(tǒng)的設(shè)計目標(biāo)——它們確實(shí)偶爾會有 bug。Node.js 的緩存對象,就值得讀一讀。 你要是問一些人,他們會說如果使用不安全的代碼,Rust 相比帶有內(nèi)存回收的編程語言是不安全的——包括最流行的 Web 框架 Actix(譯者注,Actix 是 Rust 的 Actor 異步并發(fā)框架,基于 Tokio 和 Future,開箱具有異步非阻塞事件驅(qū)動并發(fā)能力,其實(shí)現(xiàn)低層級 Actor 模型來提供無鎖并發(fā)模型,而且同時提供同步 Actor,具有快速、可靠,易可擴(kuò)展 https:///),因?yàn)椴话踩a允許原始指針的延遲。 如果你正在寫一個視頻游戲,暫停執(zhí)行垃圾收集是不好的。如果你在編寫微控制器代碼,任何內(nèi)存“開銷”或浪費(fèi)都是非常糟糕的。但是大多數(shù) Web 應(yīng)用程序可以節(jié)省一點(diǎn)內(nèi)存開銷來換取生產(chǎn)性能。 Rust 的其它屬性面對的爭議幾乎一樣。它的并發(fā)特性是太神奇了,如果你在做一些復(fù)雜的事情,需要快速響應(yīng),這當(dāng)然很棒。但如果情況不是這樣呢?至少可以說,Rust 的異步生態(tài)系統(tǒng)面臨著很大挑戰(zhàn):各種不相關(guān)的領(lǐng)域中有著不同的異步實(shí)現(xiàn),比如 tokio。 相比較之下,Python 的 Tornado 和 Twisted 異步實(shí)現(xiàn)的很奇怪,Node.js 異步實(shí)現(xiàn)的很好,但語法都很丑陋。 我確信,Rust 的異步將會穩(wěn)定和統(tǒng)一,未來會更容易操作,但我現(xiàn)在就要用啊。 很多人正在學(xué) Rust,用 Rust 編寫 CLI 應(yīng)用程序或底層代碼,并且玩得非常開心。使用 Rust 編寫普通 Web 應(yīng)用程序的人明顯少很多。 這是技術(shù)選擇中的重要部分:是否有人在使用該工具?他們大致在同一個領(lǐng)域嗎?不幸的是,Rust 生態(tài)系統(tǒng)中許多令人難以置信的令人興奮的工作與 Web 應(yīng)用服務(wù)器無關(guān)。的確存在一些很有前途的 Web 框架——甚至更高層次的框架,但毫無疑問,它們市場很小。即使是主要的 Web 框架 Actix 也只有幾個頂尖貢獻(xiàn)者。 如果 Rust 以目前的速度增長,那么社區(qū)中的 Web 部分將達(dá)到一個臨界值,但我認(rèn)為沒有足夠多的人使用 Rust 作為網(wǎng)站的實(shí)用工具。與其它社區(qū)相比,有很多公司致力于使用現(xiàn)有的工具來構(gòu)建 Web 應(yīng)用程序,這些工具不是最前沿的,但足夠?qū)⒊墒旒夹g(shù)與新技術(shù)區(qū)分開來。 這一部分不僅僅是 Rust,它還涉及 GraphQL 生態(tài)系統(tǒng),Rust 參與這個生態(tài)系統(tǒng)就是一個例子。 N+1 問題是每個構(gòu)建 Web 應(yīng)用程序的人都應(yīng)該知道的。要點(diǎn)是:你有一頁照片(一次查詢),你要顯示每張照片的作者,會有多少次查詢:1,合并照片和作者,或者在檢索照片后對每張照片進(jìn)行查詢以獲取作者?或者兩次,第二次查詢 ids 中的 user.id,一次獲取所有作者,然后重新設(shè)置他們的照片屬性。 N+1 查詢通常優(yōu)先使用數(shù)據(jù)庫解決:比如將 N+1 查詢改為單個查詢,會帶來明顯的性能優(yōu)化。我們有很多方法來嘗試和解決這些問題:你可以編寫 SQL,并嘗試使用 CTE 和 JOIN 在單個查詢中完成大量工作,就像我們在 Observable 中所做的那樣,或者使用像 ActiveRecord 這樣的 ORM 層將 N+1 查詢轉(zhuǎn)換為可預(yù)測查詢的快速方法。 Juniper 是一個用于 Rust 應(yīng)用程序的 GraphQL 服務(wù)。GraphQL 基本上都是由前端應(yīng)用程序定義查詢,而不是后端。給它一系列可以查詢的東西,然后應(yīng)用程序(React 或其它)將任意查詢發(fā)送到后端。 這會讓后端變得復(fù)雜。任何 SQL 級別的優(yōu)化都不可能做到——你的服務(wù)器正在編寫動態(tài) SQL,優(yōu)化只能依賴 GraphQL 服務(wù),但它不會總是有效。例如:Juniper 默認(rèn)情況下執(zhí)行的是 N+1 查詢,解決方案 dataloader 還比較粗糙且需要單獨(dú)維護(hù)。因此,最終您將擁有一個非??斓膽?yīng)用程序?qū)?,但它所有的時間都花在了極其低效的數(shù)據(jù)庫查詢上。 總之,GraphQL 與 NoSQL 數(shù)據(jù)庫配合使用效果非常好,它可以快速為這些類型的請求提供服務(wù)。我確信 Facebook 內(nèi)部有一些特定的數(shù)據(jù)庫與 GraphQL 結(jié)合在一起使用效果非常棒,但業(yè)內(nèi)其他企業(yè)則非常依賴 Postgres 和同類產(chǎn)品。 首先,本文提到的問題并不針對在通用場景使用 Rust,只針對將 Rust 用于特定目標(biāo)和生態(tài)系統(tǒng),簡單說就是 Web API。 注意事項(xiàng) 1:一般情況下,你可以用任何編程語言搭建網(wǎng)站,還記得基于 C++ 實(shí)現(xiàn)的 OkCupid 嗎?(譯者注,OkCupid 是美國一個大型線上交友網(wǎng)站)還有一個非常流行的星象應(yīng)用程序,Co-star,它全部是用 Haskell 編寫的。如果你擅長其它編程語言,或者可以招聘到擅長這些編程語言的工程師,你一樣可以取得成功。 注意事項(xiàng) 2:我試圖構(gòu)建的是重 CRUD(增刪改查)的 Web 應(yīng)用程序 API。它可能不算是一個 Web“服務(wù)”——主要是快速、無數(shù)次地執(zhí)行同一個操作,而是一個 Web“應(yīng)用程序”——執(zhí)行了許多不同的操作,包含了相當(dāng)多的業(yè)務(wù)邏輯。如果你要開發(fā)的東西跟我在做的不一樣,那我的建議可能就不適合你。如果你需要的是快速執(zhí)行一兩個操作,比如你正在寫一個支付網(wǎng)關(guān)或語音消息應(yīng)用程序,那 Rust 可能效果還是不錯的。 注意事項(xiàng) 3:這篇文章寫于 2021 年 1 月,如果接下來社區(qū)繼續(xù)發(fā)展,Rust 將得到持續(xù)的改進(jìn),會變得更好并更易于 Web 應(yīng)用程序開發(fā)。 總而言之,我真的很喜歡使用 Rust,這是一門美麗的編程語言,有很多很酷的想法。希望很快,Rust 會成為能用來構(gòu)建我想做的東西的最合適的工具。不過,現(xiàn)在我想做的很多東西都要采用不同特性的編程語言才能更好地運(yùn)行。 原文鏈接: https:///2021/01/15/rust.html |
|
來自: 西北望msm66g9f > 《編程》