日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

【CSDN 編者按】 本文作者 Adam Chalmers 是一名 Cloudflare 工程師,最近他分享了為什么會選擇使用 Rust。

作者 | Adam Chalmers 責(zé)編 | 夢依丹

出品 | CSDN(ID:CSDNnews)

鏈接:https://blog.adamchalmers.com/why-rust-on-backend/

譯者:彎月

近幾年來,我一直在使用 Rust 作為 Cloudflare 上的高級語言。我所需要的高級語言并不需要注重性能。我主要用這門語言來開發(fā) API 服務(wù)器,總體延遲并不重要。我完全可以使用垃圾收集語言或解釋語言,因為我不需要為了加快性能而壓榨出每一微秒。我只希望服務(wù)器保持正常運行,并讓我快速發(fā)布功能。

那么,為什么我要使用 Rust 來完成這樣的任務(wù)呢?盡管 Rust 號稱是低級系統(tǒng)語言,但實際上它的表現(xiàn)完全不輸于高級語言。下面是我考慮使用 Rust 的原因,即便是對性能沒有太高要求的項目也可以使用 Rust。

開發(fā)人員了解并喜歡 Rust

這個原因很簡單。我個人很喜歡 Rust,而且我聘請了喜歡 Rust 的開發(fā)人員。我們使用 Rust 開發(fā)軟件的效率非常高。那么,對于創(chuàng)業(yè)公司來說,如果開發(fā)人員不太了解 Rust,但公司愿意花大量時間讓大家學(xué)習(xí),應(yīng)該堅持選擇 Rust 嗎?不贊成。我們之所以選用 Rust,是因為我們喜歡 Rust,用 Rust 編程會讓我們感到快樂。

我必須強調(diào):如果團隊中沒有人熟悉 Rust,那么讓所有開發(fā)人員學(xué)習(xí) Rust 的成本將會很高。他們需要很長一段時間,才能使用Rust高效工作,你需要指導(dǎo)和支持他們。在此期間內(nèi),你們的生產(chǎn)力會很低下。你應(yīng)該選用團隊成員都知道的語言,除非你真的非常需要 Rust。

我很幸運,因為我的團隊成員都熟悉 Rust,喜歡 Rust,而且大家都希望成為更好的 Rust 程序員,所以這不是問題。

注重性能的服務(wù)

我們團隊為 Cloudflare 構(gòu)建了 Data Loss Prevention,這個服務(wù)本質(zhì)上是對某些公司網(wǎng)絡(luò)的流量進行“掃描”,以確保沒有人惡意或無意地泄露私人數(shù)據(jù)。例如,檢測并阻止黑客將數(shù)百萬個信用卡號碼從你的數(shù)據(jù)庫上傳到 pastebin.org,或者阻止某人將帶有特定 office 標簽的 word 文檔通過電子郵件發(fā)送到 yahoo.com的電子郵箱。

實際掃描 HTTP 流量以防止數(shù)據(jù)丟失的服務(wù)叫做 dlpscanner。從一開始,我們就知道 dlpscanner 對性能非常敏感,因為它代理了大量的 HTTP 請求,我們不希望在打開 DLP 時用戶瀏覽網(wǎng)頁速度變慢。所以,我們使用Rust編寫了這個部分。對于后端 API,我們有兩種選擇:Rust 或 Go。在考慮了兩種語言的復(fù)雜性后,我們決定使用Rust,因為我們不想在代碼庫中添加第二種語言。

軟件問題

當初在規(guī)劃后端 API 時,我們知道后端必須與 dlpscanner 進行互操作。它需要共享很多類型,例如用戶配置。API服務(wù)器將用戶配置序列化為 JSON,而 dlpscanner 在需要掃描請求時反序列化這個 JSON。

我更傾向于使用 Rust 編寫所有的序列化以及反序列化邏輯,而不是使用兩種語言定義我的模型,并檢查語言 A 是否可以反序列化語言 B 序列化的數(shù)據(jù)。我知道有很多工具可以簡化不同服務(wù)之間的互操作,例如 Captain Proto 和 Protocol Buffers,但是跨語言模式和生成的代碼綁定非常煩人。當然,我也可以直接編寫一些JSON轉(zhuǎn)換,并進行充分的單元測試。但我感覺編寫普通的Rust代碼似乎會簡單許多。

從根本上來說,我喜歡系統(tǒng)的不同部分之間可以共享代碼。無論是注重性能的服務(wù),還是對性能并不敏感的服務(wù)都使用了Rust,這樣可以大大簡化整個代碼庫。

個人問題

在多種編程語言之間切換上下文很難。每次打開Go或JS代碼,我都需要一些時間來提醒自己:“公開字段的首字母需要大寫”,“別忘了各種的陷阱”等等。堅持使用一種語言可以減輕我的負擔(dān),而且還可以最大限度地減少新團隊成員需要學(xué)習(xí)的知識。

Serde

我非常喜歡Serde,所以打算專門介紹一下。在最初使用Go的幾個月里,我為JSON反序列化編寫了很多單元測試,由于Go采用了基于注釋的方法,因此即便某個地方輸入錯誤,編譯器也無法捕捉到。例如,在下面的 Go 代碼中:

type response struct{ PageCount int`json: "pageCount"` FirstNames [] string`json: "firstNames"` }

我需要給每個字段加注釋,說明JSON序列化或反序列化的鍵應(yīng)該是什么。這種方法本身沒問題,但如果你有很多字段,而且需要手動將它們統(tǒng)統(tǒng)轉(zhuǎn)化為蛇形命名,而不是駝峰式命名,就會非常麻煩。一旦輸入錯誤,就會得到一個運行時錯誤。此外,你必須給每個字段加注釋,因為Go的JSON包只能反序列化公共字段(以大寫字母開頭),而其他服務(wù)希望看到的是以小寫字母開頭的字段。

但在Serde,我只需要這么寫:

# [serde(rename_all = "camelCase")] structResponse{ page_count: i32, first_names: Vec<String>, }

這樣就可以生成反序列化的代碼,不需要單元測試。Serde 提供了許多開箱即用的其他屬性來幫助自動化 JSON 任務(wù)。對API后端來說,序列化與反序列化 JSON 是一個非常核心的問題,因此你應(yīng)該確保這部分代碼簡單明了,而且不需要大量的自定義邏輯和單元測試。

Serde 很不錯,因為剛開始的時候你可以只支持 JSON,然后再添加其他序列化標準的支持。如果想著對性能非常敏感的代碼中重用這些類型,serde 可以處理大量其他數(shù)據(jù)格式,而且這些數(shù)據(jù)格式的序列化和反序列化速度更快。

在之前的項目中,我遇到過很多 JSON 序列化和反序列化的錯誤,但自從使用Serde以來,我從未遇到過任何問題。它為我節(jié)省了很多時間。如果我需要編寫一個嚴重依賴反序列化數(shù)據(jù)的新項目,我會嘗試使用Rust(或者JS,如果我知道數(shù)據(jù)只會以 JSON 格式傳輸并且兩端都可以使用 JS的話)。

數(shù)據(jù)庫

Rust 在數(shù)據(jù)庫方面的表現(xiàn)并不出色,但我認為它也非常擅長數(shù)據(jù)庫的處理。我很喜歡使用 Diesel,它可以根據(jù) SQL 的遷移腳本生成類型化的 SQL 模式,然后再為你生成所有的 SQL 查詢。這就解決了以下幾個問題:

  • 在刪除或重命名 SQL 表中的列時,如何檢查所有現(xiàn)有查詢已被更新,可以理解最新的數(shù)據(jù)庫模式?
  • 如果在代碼中為 SQ 的L表或行建模,并添加/更改/刪除列,如何檢查所有代碼類型是否準確地建模了 SQL 類型?這稱為雙重模式問題。保持代碼模式(JS、Go、Rust 等等)與 SQL 模式同步是非常繁瑣的工作。
  • 我不喜歡所有語言中的對象關(guān)系映射器,但 Diesel 非常好,因為當我更新 SQL 模式時,Diesel 將重新生成合適的 Rust 模型,而且 Rust 代碼和 SQL 語句之間幾乎所有的不匹配都變成了編譯器錯誤,修復(fù)起來很方便。

在 Rust 類型系統(tǒng)中構(gòu)建 SQL 類型系統(tǒng)的模型是一項非常了不起的工作,不過它也會引發(fā)很多非常煩人的問題,因為 Diesel 類型非常復(fù)雜。其中包括:

  • 超過 60 行的錯誤信息。
  • 毫無意義的錯誤信息(比如“這個特性沒有實現(xiàn)”,好吧,我知道了,那么你能告訴我為什么沒有嗎?不行?好吧,讓我獨自哭一會兒)。
  • 很難提取共用代碼,放入共享函數(shù)中,因為兩個看起來相似的查詢具有截然不同的類型。

但總的來說,如果應(yīng)用程序中的許多功能都非常依賴于數(shù)據(jù)庫,那么我認為確保數(shù)據(jù)庫查詢得到正確的類型檢查是值得的。數(shù)據(jù)庫查詢不是 API 后端中的一些可選的附加功能,它們幾乎就是整個代碼庫。所以我們必須確保它們的正確性。

當然,你可以手動編寫所有 SQL 查詢,并非常仔細地進行單元測試,但是你需要認真考慮單元測試,保證它們與生產(chǎn)模式保持同步,并確保不會出現(xiàn) SQL 注入。雖然有時 Diesel 很讓人頭疼,但總的來說值得考慮。

有了 Diesel 和 Serde,API 中幾乎所有重要的代碼(讀取請求、執(zhí)行數(shù)據(jù)庫查詢和編寫響應(yīng))都可以生成了,這樣你就有更多時間編寫業(yè)務(wù)邏輯、發(fā)布功能并專注于業(yè)務(wù)領(lǐng)域建模。

更好的業(yè)務(wù)領(lǐng)域建模

存儲用戶配置的后端 API 可以在軟件中正確地建模現(xiàn)實世界,這一點很重要。如果用戶利用你的軟件表示辦公室的布局,那么你的類型系統(tǒng)就應(yīng)該能夠模擬辦公室,而不是讓用戶推送無效的配置。

如果可能的話,我們都希望在編譯時檢測到這些無效配置,而不是等到運行時,以最大程度地減少測試和錯誤檢查的代碼。如果某種配置不會出現(xiàn)在現(xiàn)實世界中,例如任何用戶的辦公室都不可能位于兩個時區(qū),那么你的軟件模型就不應(yīng)該表示具有兩個時區(qū)的辦公室。這個概念被稱之為“使非法狀態(tài)無法表示”,這方面的文章有很多。

Rust 有兩個功能可以幫助你準確地建模業(yè)務(wù)領(lǐng)域:枚舉和不可克隆類型。

枚舉

有一個非常巧妙的概念,叫做“求和類型”,根據(jù)使用的語言不同,又被稱作“標記聯(lián)合”、“代數(shù)數(shù)據(jù)類型”或“具有關(guān)聯(lián)值的枚舉”。我非常喜歡求和類型。我也曾在Haskell的業(yè)余項目中使用過,我在擔(dān)任iphone開發(fā)人員時使用Swift,如今在Cloudflare中使用Rust。因為它們非常適合業(yè)務(wù)領(lǐng)域建模。

你可以利用枚舉確保函數(shù)要么返回一個錯誤,要么返回一個 Person 結(jié)構(gòu)。不可以同時返回兩者,也不可以哪個都不返回。必須是兩個選項之中的一個。當沒有枚舉時,比如在Go中,我需要仔細閱讀每個函數(shù)并檢查理應(yīng)返回(Person, *err)的函數(shù)永遠不會出現(xiàn)哪個都不返回的現(xiàn)象。

我喜歡用枚舉對域進行建模。我非常希望用戶能夠使用 TCP 套接字或 Unix 套接字啟動我的軟件,并且知道編譯器會檢查你不會意外地傳遞任何一種套接字、第三種套接字或其他東西。

準確地建模業(yè)務(wù)領(lǐng)域是高級API必須實現(xiàn)的。正確性很重要。所以,如果我需要確保軟件模型準確地代表現(xiàn)實世界,那么Rust是更好的選擇。

不可克隆類型

幾年前,我需要在Cloudflare上為一組(10個)IP地址建模。這是因為Cloudflare邊緣網(wǎng)絡(luò)有10個公共 IP,而Cloudflare在服務(wù)器上運行,并連接到了其中的4個IP,以實現(xiàn)負載平衡。

如果其中一個 IP 是“不健康的”,并且斷開了Cloudflare,那么Cloudflare就應(yīng)該避免重復(fù)使用這個IP,轉(zhuǎn)而使用一些以前沒有使用過的 IP。對于這個建模,一種常見的方法是為每個IP分配三種可能的狀態(tài):正在使用、未使用以及以前使用過但現(xiàn)在不健康。這些IP中的每一個都可以分配給4個長期存在的 TCP 連接之一。

這個問題聽起來像是很容易解決,但我們很難為“每個IP地址最多可以分配給一個連接”的想法建模。我不得不編寫大量的單元測試來覆蓋兩個不同的連接獲取相同 IP 地址的極端情況。這很難,因為在 Go 中,每個值都可以被復(fù)制。確保只有一個特定字符串的副本,比如“104.19.237.120”,需要付出大量的努力。一般Go函數(shù)會復(fù)制值,或復(fù)制指向該值的指針,因此很難確保只有一個 goroutine 正在讀取值。

然而,Rust可以輕松確保特定值僅在一個地方“使用”。無論在任何時候,都只能有一個 &mut 引用一個值,所以只需讓“使用”該值的函數(shù)獲取 &mut 即可。或者,也可以讓類型不實現(xiàn) Clone,并確保“使用”它的函數(shù)完全擁有該值。這個值會被移動到函數(shù)中,而函數(shù)完成后會“返回”該值。

所以,如果我想用Rust實現(xiàn)這個系統(tǒng),只需要保留一個包含10個IP地址的HashSet,并確保每個個連接都將 &mut 轉(zhuǎn)移到正在使用的 IP。我還要確保 IP 是新類型UncloneableIp(std:.NET::IpAddr),并且我沒有為該新類型派生克隆。

老實說,這種問題在實踐中并不常見,但遇到這樣的問題時,檢查每個函數(shù),并確保它們都沒有復(fù)制值或共享引用是一件非常討厭的事情。

可靠性

對于初創(chuàng)公司來說,性能可能不是問題,但可靠性有可能是問題。客戶不喜歡為離線服務(wù)付費。我個人就曾有過這樣的經(jīng)歷,維護了一些非常不可靠的服務(wù)。

避免給自己挖陷阱

我的 Rust 后端服務(wù)基本不會崩潰。沒有引發(fā)恐慌的 nil 解引用。當然我們還是應(yīng)該小心 Option,.unwrap 一個 Option 的值就有可能引發(fā)崩潰。但是,這些問題很容易在代碼審核中發(fā)現(xiàn),看到 .unwrap 我們就應(yīng)該警惕程序崩潰。在實踐中,與 unwrap 相比,Rust 有更好的方法來處理 Option,所以在我們的代碼審查中很少出現(xiàn)這種情況。在我們的代碼庫中,95% 的 unwrap 都是單元測試在使用。

這種可靠性必然需要開發(fā)人員付出努力,比如考慮如何正確地使用模式匹配所有的結(jié)果和選項值。但對于許多領(lǐng)域來說,這種權(quán)衡是有意義的。我曾碰到過很多失敗的項目,如果能避免半夜被警報吵醒,那么我很愿意付出一些努力。

資源管理

Rust 不會使用太多內(nèi)存或泄漏資源(如 TCP 連接或文件描述符),因為當函數(shù)終止時,一切都會被丟棄和清理。但也有一些例外,比如可能會“泄漏任務(wù)”,我的 Go 服務(wù)就會泄露 goroutines。你必須確保在所有地方都使用適當?shù)某瑫r。

我吸取的教訓(xùn)是,性能問題最終都會演變成可靠性問題。如果服務(wù)泄漏內(nèi)存的時間足夠長,或者攝入的數(shù)據(jù)足夠多,那么性能瓶頸最終就會導(dǎo)致服務(wù)崩潰。雖然并不是每個人都會遇到這個問題,但是如果你認為你的流量或使用量有可能在一天內(nèi)暴增幾個數(shù)量級,例如出現(xiàn)一大批新用戶注冊,那么就值得考慮。

總結(jié)

我認為 Rust 作為一種高級語言可以出色地完成工作。特別是在處理 Web 服務(wù)時,Rust 可以通過 serde 和 Diesel 等庫為你節(jié)省很多時間。類型系統(tǒng)可以讓你更輕松地建模業(yè)務(wù)領(lǐng)域,而且你的服務(wù)也不會經(jīng)常中斷。

但是,如果你的團隊中沒有人熟悉 Rust,或者沒有太多經(jīng)驗,那么使用 Rust 構(gòu)建 Web 服務(wù)可能是一個非常糟糕的主意。Rust 的難度曲線已經(jīng)回落了,但依然非常高,你應(yīng)該使用團隊熟悉的語言。

網(wǎng)友:以上理由可以套在JS/JAVA/Python/ target=_blank class=infotextkey>Python

評論1:我想指出一點有可能出現(xiàn)的副作用。如果你有一個系統(tǒng)開發(fā)人員組成的團隊,每個人都非常熟悉 Rust,而團隊的下一項任務(wù)是構(gòu)建一個 Web API 的中間件,那么 Rust 是最顯而易見的選擇,因為每個人都熟悉它,而且喜歡它。但是,除非你打算永遠讓這些人負責(zé)這個 Web API,否則這個決定會導(dǎo)致你無法招聘任何熟悉 C#、JS、Java、Go、Python 等更容易構(gòu)建后端的語言的開發(fā)人員。這個決策將你的招聘范圍縮小到了 Rust 專家,哪怕你的需求是剛剛會啟動 Flask 服務(wù)器的畢業(yè)生都能搞定的。

評論2:這種說法可以套在任何不是 JS/Java/Python 的語言上。實際上,Rust 并不難學(xué)。Rust 的 Web 棧非常簡單,只要幾天就能學(xué)會。優(yōu)秀的開發(fā)人員會使用多種語言,而且喜歡使用多種語言。如果你不要求必須有十年工作經(jīng)驗,那么就能招聘到喜歡挑戰(zhàn)自己、喜歡學(xué)習(xí)新知識的人。

分享到:
標簽:Rust
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定