使用 C++ 構建雲資料庫後,我們後悔了!

使用 C++ 構建雲資料庫後,我們後悔了!

【CSDN 編者按】無論對於哪一個大的專案來說,重寫都不是一個簡單的決定。對於編寫資料庫系統來說,使用C++看起來是個不錯的決定,畢竟大多數知名的資料庫系統,包括MySQL、PostgreSQL、Oracle和IBM Db2,都是用C/C++建立的。但是一個處在發展前期的初創公司,在經過深思熟慮之後,此公司CEO決定將使用C++開發了7個月的資料庫系統重寫,並且遷移到了Rust,這是為什麼呢?

原文連結:https://singularity-data。com/blog/building-a-cloud-database-from-scratch-why-we-moved-from-cpp-to-rust/

譯者 | 章雨銘 責編 | 屠敏

出品 | CSDN(ID:CSDNnews)

以下為譯文:

作為一家早期的資料庫初創公司,本來我們的程式碼庫是用C++寫的,開發了7個月之後,完全刪除了C++程式碼庫,並且用Rust重寫了所有的內容。下面我將講述這個決定的原因,以及為什麼這是最好的決定。

RisingWave是一個雲原生流媒體資料庫,這個系統是為了降低雲中構建實時應用程式的複雜性和成本而建造的。

在2021年初開始構建RisingWave時,是用C++寫的。創始團隊也是由幾位經驗豐富(擁有10多年相關經驗)的C++工程師組成的。因此,使用C++似乎是理所當然的,沒有經過深入的考慮。開發的頭幾個月很順利,我們全力以赴地構建這個優秀的資料庫,夢想著RisingWave能夠撼動現代資料堆疊。

隨著團隊日益壯大,使用C++導致的缺點開始顯現,比如不可讀的編碼風格、記憶體洩露、分段錯誤等等。團隊開始懷疑,用C++來編寫新資料庫系統真的合適嗎?

開發耗時7個月後,經過整整一個月的討論,我們做出了一個艱難的決定:從C++遷移到Rust。

這個決定意味著什麼?意味著,一個由10多名經驗豐富的工程師組成的團隊,不得不從頭開始寫整個系統!我們7個月的努力都白費了。對於一家早期的初創公司來說,這無疑是一個瘋狂的決定。因為,在這個競爭激烈的科創公司中,時間就是一切。

做出這個決定後,我們花費了大約兩個月的時間完全刪除了C++程式碼庫,一共276,406行程式碼,並且用Rust重寫。現在已經過去了10個月,這個決定讓RisingWave執行得很好,其原始碼可供Apache許可證2。0下的每個人訪問。有超過60位貢獻者一起開發雲原生流媒體資料庫。RisingWave能夠在重寫後倖存下來,而且在短短一個月內在GitHub上獲得了超過1,600顆星星,我們為此感到興奮且自豪。

使用 C++ 構建雲資料庫後,我們後悔了!

Rust社群快速增長,許多工程師可能會考慮是否用Rust編寫他們的專案,就和當初我們一樣。所以我們願意分享一些經驗,關於遷移到Rust的原因,以及在過程中遇到的困難。

首先是對在開發過程中C++帶來問題的回顧。

選C++不會錯,但它並不總是最好的

C/C++無疑是構建資料庫系統最流行的程式語言之一。大多數知名的資料庫系統,包括MySQL,PostgreSQL,Oracle和IBM Db2,都是用C / C++建立的。所以它仍然是一種可行,重要且相關的語言。選擇C++來構建一個全新的資料庫系統不會是一個錯誤的決定,但這並不意味著C++是最佳選擇,特別是對於一個旨在從頭開始創新大型資料庫系統的早期創業公司來說。

那麼使用C++帶來了哪些好處和麻煩呢?

好處

C++能夠讓開發人員開發出高效能的程式。它提供了對記憶體和計算的細粒度控制,而沒有自動垃圾回收的成本。此外,C++程式碼可以編譯成組合語言,以便在作業系統上直接執行,而不是依賴於直譯器或語言執行時。

C++已經被證明是系統程式設計的可行語言。大量的資料庫都是用C/C++構建的。因此,足以讓決策者相信,選擇C++不會錯。

壞處

C++為程式設計師提供了很大的靈活性,但這是有代價的。編寫時非常容易出現錯誤,而且有的錯誤會帶來嚴重的後果。除錯C++程式非常困難,特別是對於併發程式設計。

管理依賴關係可能很麻煩。儘管有一些工具(例如 CMake)可以自動配置C++專案的編譯,但開發人員仍然需要手動配置和安裝依賴庫。

大麻煩

STL 庫缺乏對某些現代程式設計工具的支援,例如,本機協同例程支援。因此,開發人員必須依賴許多社群專案,並且大多數缺乏長期支援。

很難保證質量。C++支援如此多的功能,不同的開發人員可以用截然不同的風格編寫C++。隨著團隊日益壯大,可讀性就無法得到保證。此外,識別C++程式碼中的錯誤也並非易事。因此,審查C++程式碼可能會變得令人生畏。

Rust是更優的選擇

既然用C++來構建資料庫系統來說並不算太糟糕,那麼為啥那麼要重寫程式碼庫呢?做出這個決定,我們是經過深思熟慮的。

使用 C++ 構建雲資料庫後,我們後悔了!

流資料庫通常用於對延遲非常敏感的關鍵型任務,因此,只有符合以下要求的語言才能用於構建RisingWave:

保證零成本抽象(構建一個抽象的時候這個抽象不會造成額外的負擔),這樣就不會有效能上限;

不需要執行時垃圾回收,以便控制可能由記憶體管理引起的延遲峰值。

為了獲得頂尖的效能,在這兩個基本要求上不容妥協。

基於以上考慮,Rust成為了更優的選項。雖然這兩種語言都能為開發人員提供零成本抽象和對記憶體管理的完全控制。但是,總的來說,Rust是促進高效和大規模協作的更好選擇。以下是四大原因:

Rust很安全。Rust 透過引入所有權規則來保證編譯時的記憶體安全和執行緒安全。它甚至超越了RAII(RAII 是C++中使用的常見記憶體管理機制)。還有兩個優點。第一個是不言而喻的:一旦 Rust 編譯器驗證了程式,就不會在執行時出現分段錯誤或資料爭用,否則將需要數十個小時的除錯,尤其是在高度併發且主要是非同步的程式碼庫中。第二個是:Rust 編譯器只是限制錯誤的型別,這減少了可能導致此類錯誤行為的錯綜複雜的交織程式碼片段。

Rust易於使用。C++為開發人員提供了最大自由度,但有時,這會適得其反。例如,在C++中,template會在編譯時擴充套件,以以檢查特定型別是否不可呼叫任何操作。在 Rust 中,編譯器可以在呼叫站點檢查型別的有效性,而不是執行擴充套件。這種差異使C++template的錯誤資訊更加難懂,通常需要經驗豐富的C++高手來破譯。另一個例子是C++中隱式轉換的廣泛濫用。隱式轉換可能會幫助開發者減少編碼,但是更容易導致出錯。

Rust易於學習。對於經驗豐富的C++程式設計師來說,Rust 很容易學習。Rust 對於初學者來說可能具有挑戰性。但事實證明,公司的實習生並非如此。他們在一兩週內就學會了 Rust——即使之前沒有 Rust/C++專業知識——因為需要記住的隱式轉換和 過載決議更少。檢查基本的 Rust 程式碼對我們的同事來說輕而易舉。現在,花在審查初學者的 Rust 程式碼上的時間遠遠少於C++程式碼。

不安全的Rust是可管理的。 由於Rust靜態分析器的保守性,有可能會發生這樣的情況:只有不安全的Rust才能使不可能成為可能。一個典型的例子是建立一個自我參照的型別。或者我們必須透過不安全的方式獲得額外的效能,即直接操作壓縮記憶體表示中的bit。當然,有人會質疑:這是否會使程式碼庫變得脆弱?對於RisingWave,根據經驗,答案是否定的。兩個主要的用例是LRU快取和Bitmap,它們在總共17萬行的程式碼中只佔不到200行。採用這種方法,首先在安全的Rust中編碼,只有在有具體的證據和堅實的論據時才採用不安全的方法,所以這麼做不會讓人擔憂。

不好的一面

雖然Rust滿足了我們的大多數要求,但也有其不好的一面:

分散的非同步生態系統:在沒有對非同步執行時做出初步決定的情況下,我們花了幾個月的時間擺脫了futures-rs和async-std,並最終切換到tokio-rs。

繁瑣的錯誤處理:需要手動儲存和實現對錯誤的回溯捕獲,以獲得回溯。

對非同步迭代器的支援不充分。由於traits中沒有對穩定生成器和async fn的本地支援,所以我們需要使用第三方庫來實現支援。然而,與待定的標準實現相比,這些庫分配了額外的Boxes,最終會導致效能的下降。另外,使用這些庫中的宏會妨礙IDE的正常工作,阻礙程式設計師開發。

通用關聯型別 (GAT) 的實際限制。GAT是許多現有/待定功能的基礎,例如traits中的靜態/動態async fn。然而,對GAT的完全支援會產生複雜的技術問題,可能需要比預期更長的時間來解決。在此之前,我們必須使用各種技巧來繞過限制,或者忍受次優的解決方案。

儘管如此,但是我們的團隊中有這麼多才華橫溢的工程師,在控制負面影響的同時,仍然能夠顯著提高生產力和程式碼質量。

根據具體情況做決定

這篇部落格並不是要說服每個資料庫開發團隊放棄他們的整個C++程式碼庫,並從頭開始在 Rust 中重寫他們的系統。相反,這篇部落格主要是講述做出這樣決定的原因。事實上,儘管 Rust 帶來了明顯的好處,但如果沒有以下關鍵因素,我們可能不會做出這個艱難的決定:

當時我們正在重構程式碼庫以適應我們的新系統架構,重寫(至少一部分)程式碼庫是不可避免的。

我們團隊中有一些Rust愛好者,他們不斷向其他工程師宣傳 Rust,並說服整個團隊,用Rust重寫是一個實用的選擇。

我們的團隊不斷壯大,這加快了程式碼庫的重寫的效率。

總結

Rust 是一種很酷的程式語言,值得每一個人嘗試。但是不要僅僅因此就重寫你的專案。如果你正在考慮是否要用Rust重寫你的專案,那麼請問問自己以下問題:

低階程式設計、效能、記憶體安全和包管理是否是您專案所關注的問題?

你的團隊中有沒有Rust專家可以幫助避免潛在的麻煩?

重寫這個專案需要多長時間?

你們會因為重寫而錯過任何關鍵的截止日期嗎?

你們有關於 Rust 的內部培訓計劃嗎?

你可以在仔細考慮這些問題的答案後再做出決定。當然,Rust(或任何其他語言)永遠不會決定你專案的命運。但是,做出明智的選擇可能會為你節省數百甚至數千人月的時間。

END

《新程式設計師001-004》全面上市,對話世界級大師,報道中國IT行業創新創造

使用 C++ 構建雲資料庫後,我們後悔了!

頂部