尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️
作者 | Thierry Schellenbach
譯者 | 安翔
為什麼 Stream 這家公司要從 Python 遷移到 Go?他們看中 Go 語言的哪些特性?
Stream 最近將其後端核心服務從 Python 改成了 Go。雖然他們的某些模塊仍然在使用 Python,但是公司已決定從現在開始使用 Go 來編寫對性能要求較高的代碼。文中,Stream 的 CEO 兼創始人 Thierry Schellenbach 將解釋他們決定轉向 Go 的原因。
影響項目或者產品編程語言選型的因素有很多。與任何技術決策一樣,選擇編程語言時同樣需要多方面權衡,即使這樣,最終的選擇結果都很難是完美的。我們最近將後端的核心服務從 Python 改成了 Go,原因有很多,好處也很多。
為了理解這一變化的重要性,需要先了解我們的產品。Stream 是一套用於構建、伸縮、定制化新聞源和活動流的 API。每個月為 3 億多用戶提供約 10 億次 API 請求。我們尤其關注性能和可靠性,這兩點因素決定了我們制定的每項技術決策。
性能更優
Go 最大的賣點在於它的性能,無論在運行還是編譯時它都有突出的性能優勢。它與 Java 或者 C++ 的運算速度幾乎相當。在實際使用中,我們發現它比 Python 大約快 30 倍。
選擇快速工具對提升系統性能非常重要,因此我們對 Cassandra、PostgreSQL、Redis 以及其他一些技術進行了優化。然而,很多時候我們發現系統仍然存在瓶頸,而瓶頸正好在於我們的編程語言 Python。Python 在執行序列化、排序和聚合等計算密集型任務時需要花費很長的時間,有時比從網路上存取和檢索數據花費的時間更長。我們知道這個時間是可以優化的。從 Python 切換到 Go 就可以縮短時間,這樣一來,應用程序代碼就更像是服務之間的黏合劑,而不再是優化中的主要瓶頸。
用 Go 編寫的 Go 編譯器也非常快。Stream 中最複雜的微服務就採用 Go 編寫,它的編譯時間僅僅需要 6 秒,Java 和 C++ 等工具鏈則慢得多,快則一分鐘,慢則數小時。
名副其實的簡單
簡單是 Go 的重要特徵!我敢向你保證,閱讀 Go 語言的代碼明顯感覺更加簡單。我們已經從多個 Python 代碼庫中遷移出來,我們發現這些 Python 代碼的風格和框架會因為作者的不同而風格各異,往往帶有很多作者個性化的東西。而 Go 恰恰相反,它推崇乾淨的代碼風格,同時要求作者編寫代碼時嚴格遵守規範,禁止作者「自作聰明」。雖然這樣有時候會使用更加冗長的代碼,犧牲了代碼的簡潔性,但是卻讓代碼更容易閱讀和理解了。這樣一來,Go 才得以加快開發人員閱讀他人代碼的速度,同時,閱讀自己曾經編寫的代碼也更容易。
原生並發性
Go 在語言層面通過 goroutine 和 channel 支持了並發。此概念源自 Tony Hoare 的 CSP 模式,它讓工程師處理並發變得不再困難。
goroutine 類似於操作系統的線程,但其運行消耗的系統資源更小,每個 goroutine 僅需幾 KB 的堆棧空間。Go 運行時可以在操作系統線程之上處理多路 goroutine。雖然在後台執行,但它對於工程師來說是可見的。單個程序擁有數千個 goroutine 也並不罕見。比如,net/http 軟件包中的服務器程序針對每個 HTTP 請求都會創建一個 goroutine。
在 Go 中啟動 goroutine 非常簡單,只需通過 go 關鍵字添加一個函數調用,即可啟動一個 goroutine,並讓該函數運行在自己的 goroutine 中。
Go 有一句重要的格言,即:不要通過共享內存來通信,相反,通過通信來共享內存 。Goroutine 之間通過 channel 進行通信,channel 的使用方法與 goroutine 一樣簡單。Channel 擁有類型,可以通過直觀的箭頭語法輕鬆做到 goroutine 之間的數據傳遞。盡管 channel 使用簡單,但是其功能非常強大。在設計時只要預先稍作考慮,與傳統的系統相比,使用 Go 便能夠輕而易舉地開發大規模並發系統。
使用簡單的並發工具可以解決那些經常導致錯誤的問題。Go 內置了競態條件檢測器,可以更輕鬆地檢測異步代碼中的競爭狀態。
語言生態
跟 C++ 和 Java 這樣已經高度普及的傳統語言相比,Go 仍然是編譯語言領域的新手。雖然目前大約只有 5%的工程師知道 Go,但是得益於它的易用性,這個數字在不斷增長。雖然 Go 語言速度快且功能強,但它只有 25 個保留字。相比於 C++ 的 92 個保留字,以及 Java 的 53 個保留字,Go 顯得非常簡潔。過多的保留字會增加工程師的學習成本。
由於 Go 上手非常容易,因此組建 Go 開發團隊相比其他語言來說更容易。Go 初學者可以很快入門並精通該語言。這使得雇主甚至可以招聘其他背景的開發人員,然後加以短期培訓即可使其成為合格的 Go 工程師。
Go 提供的內置庫開箱即用且功能強大。使用「net/http」僅需幾行代碼即可做到 HTTP 服務器,並且還支持 http/2、TLS 和 websocket。Go 社區軟件包的生態系統也很出色,已經出現了很多與 Redis、RabbitMQ、PostgreSQL、模板以及 RocksDB 相關的庫,它們運行穩定且更新頻繁。
其他優勢
在前文中我提到了 Go 並不鼓勵工程師「自作聰明」,它並沒有提供可能會節省時間的功能,比如可嵌套的三元運算符。
Go 採用另一種方式來節省時間,它既沒有選擇制表符也沒有選擇空格,而是轉而使用了 gofmt。它是一種命令行工具,可與大多數編輯器集成並自動將代碼格式化為特定的格式。即使格式不正確代碼仍會編譯,但是拉取請求會被忽略,除非代碼通過 gofmt 並且能夠保持整個代碼庫格式一致。這使得代碼評審人員能夠專注在代碼上,而不必在格式上浪費時間。
Go 有助於開發微服務。Google的 protobuf 和 gRPC 是微服務間通信的基礎,Go 對它們提供了很好的支持。作為開發人員,我們只需在清單文件中定義一項服務,工具便會自動生成客戶端和服務器端代碼,並且保證代碼的高性能以及很低的網路負載。此外,清單文件還可以被其他語言用來生成他們自己的客戶端和服務器端代碼。所以,如果我們決定用其他技術來替代部分架構,之後的任務會更加簡單。
Python vs. Go
Stream 服務強大功能之一是 feed 排名。feed 排名允許我們的用戶為 feed 指定一個評分函數,以便控制排序方式。評分算法可以提供很多變量來確定排名,其中基於流行度的一個例子可能是這樣的:
{
"functions":{
"simple_gauss":{
"base":"decay_gauss",
"scale":"5d",
"offset":"1d",
"decay":"0.3"
},
"popularity_gauss":{
"base":"decay_gauss",
"scale":"100",
"offset":"5",
"decay":"0.5"
}
},
"defaults": {
"popularity": 1
},
"score":"simple_gauss(time)*popularity"
}
-
為了支持這種排名方法,Python 和 Go 代碼都需要解析表達式計算得分。在這種情況下,我們需要將字符串 「 simple_gauss(time)* popular 」 變成一個函數,它將活動數據作為輸入,並輸出分數。
-
基於 JSON 配置創建部分功能。例如,我們希望「simple_gauss」以五天的時間窗、一天的偏移量以及 0.3 的衰減因子來調用「decay_gauss」。
-
解析「默認」配置,以便在活動數據中發現未定義的字段時進行回退。
-
使用步驟 1 中的功能對 feed 中的所有活動數據進行評分。
開發 Python 版本的排名代碼需要花費大約三天時間,包括編寫代碼、單元測試和編寫文檔。接下來,團隊需要大約兩周的時間來優化代碼。其中一項優化是將分數表達式 (simple_gauss(time)* popular )轉換為抽象語法樹。該團隊還實施了高速緩存邏輯,預先計算了將來某些時間的分數。
相比之下,開發這些代碼的 Go 版本大約花費了四天時間,並且不需要再對其性能實施進一步的優化。雖然 Python 用來開發初期版本更快,但是整體來說使用 Go 開發的工作量要小得多。
Go 的語言特性使得在優化代碼時能夠節省大量的時間。使用 Python 時,我們不得不將表達式解析為抽象語法樹,並優化和剖析每一個函數。由於 Go 比 Python 快得多,因此我們不需要花太多精力優化代碼。最終的結果是,Go 代碼的執行速度比精心優化的 Python 代碼大約快 40 倍。
用 Go 來構建 Stream 系統中的某些組件相比用 Python 花費了更多的時間。總體來說,開發 Go 代碼要花費更多的精力,但團隊用來優化代碼性能的時間則更少。
結 論
Go 非常適用於開發微服務。它的速度非常快,具有原生並發原語,完美支持多種現有工具,並且開發起來樂趣無窮。與 Ruby 或 Python 等腳本語言相比,編寫 Go 代碼可能需要更長的時間,但其維護成本要低得多,加之其代碼無需太多優化,因此你可以節省大量的時間。
需要注意的是,對於某些適合使用 Python 開發的模塊,Stream 仍然使用 Python。例如,我們的儀表板、網站以及用於個性化訂閱的機器學習都使用 Python 做到,因為 Python 提供的這些工具更好用。我們不會馬上完全棄用 Python,但是對於性能要求較高的代碼,我們今後會使用 Go 來編寫。
英文原文
InfoQer 說
你認為 Stream 進行遷移的理由充分嗎?
在你看來,Go 語言哪些特性相比 Python 是更受你推崇的?
既然 Python 有諸多不足,為什麼它最近反而還越來越火了?
歡迎在文章底部留言,大家一起討論。
今日薦文
點擊下方圖片即可閱讀
WebIDE:在瀏覽器中寫代碼的時代即將來臨?
2018 年,有哪些值得關注的運維技術熱點?第四屆 CNUTCon 全球運維技術大會正式啟動啦,包括智能化運維、Serverless、DevOps 等熱門話題,數十位大牛聯合出品,揭秘最前沿運維技術,推薦學習!點擊「閱讀原文」了解更多大會精彩。