Go 語言中的一些非常規優化

這次去 Gopher China 和不少老朋友見了個面,還有不少在微信上認識已久,一直沒見過面的網友。同時也和各個公司的一線開發們聊了聊,互相交流了彼此使用 Go 時的一些心得和痛點。

綜合近期瞭解的一些相關分享,我把到目前爲止見到的,不那麼常見的,各方對 Go 的優化和 hack 集中在這篇文章裏。因爲考慮到一些公司情況比較特殊,所以本文中列出的點就不標記是哪個公司做的了。未來他們覺得時機成熟應該也會自己出來做一些分享。

網絡方面

當前 Go 的網絡抽象在效率上有些低,每一個連接至少要有一個 goroutine 來維護,有些協議實現可能有兩個。因此 goroutine 總數 = 連接數 * 1 or 連接數 * 2。當連接數超過 10w 時,goroutine 棧本身帶來的內存消耗就有幾個 GB。

大量的 goroutine 也會給調度和 GC 均帶來很大壓力。Go 底層的網絡庫和加密庫效率也不是很高,所以在同類應用上和 C++ 等語言有較大性能差距 (內存、吞吐量)。

社區有不少使用裸調 Epoll 實現優化的庫,就不給他們打廣告了。由於用戶的 syscall.EpollWait 是運行在一個沒有任何優先級的 goroutine 中,當 CPU idle 較低時,系統整體的延遲不可控,比標準庫的延遲還要高很多。之前個人做過相關的測試,核心數的增加也會使系統相應的延遲大幅上升。

接下來不同的公司的優化思路就走向了兩個方向:

  1. 修改 runtime,在 runtime 增加用戶 Epoll 函數的回調。類似 runtime 自己實現的 netpoll 那樣。這種方式會導致 Go 本身難以升級,必須跟着有 hack 的版本走。當遇到 Go 的 bug 時會比較尷尬。

  2. 把 c 實現的網絡庫當作基礎組件,把 Go 實現的業務邏輯作爲業務嫁接在 c 庫之上。

Go 語言的強項就是在網絡編程上,現在卻逼得大家爲了優化都需要去做對 runtime 的 hack,甚至嫁接其它語言,這不能不說有點悲哀。還是希望未來官方能夠有更好的底層基礎工具來支持這種超高連接數的場景。

cgo

因爲 c 歷史悠久,所以對 cgo 的使用是難以避免的,個人見到比較多的,比如做國際化需求必須要用到的 icu 庫,只能用 cgo 來調。或者做 cv 的 opencv,也只能用 cgo。或者國密場景,也只能用 cgo。

但從 go 調用到 c,有一次棧切換,成本有些高,所以有公司實現了從 go 切換到 c 不需要切換棧的神奇調用方式,同時在棧上打標記,讓 GC 只掃描 Go 的棧而不掃描 c 的棧。

go-plugin

官方提供的 go plugin 還是比較難用的,比如要求編譯版本必須統一;加載後無法卸載等。

現在有公司基於 .got 表,實現了比官方的 plugin 更靈活的熱加載,熱卸載的動態庫。

(這條我不太懂,所以只是聽說,有問題歡迎指出

彙編優化

Go 語言的編譯後端都是 Go 自己實現的,沒有藉助以往的平臺,如 LLVM。

有人將 C 語言編寫的等價代碼用較高的優化級別,如 clang -o3,編譯爲高度優化的彙編,再翻譯爲 plan9 彙編,整合成函數供 Go 應用調用,這樣相當於在 Go 裏享受了 llvm 平臺的後端優化成果。

runtime 修改

除了前面提到的網絡編程時,epollwait 需要高優先級的 goroutine,在其它一些涉及到任務分發,任務處理的應用程序中也需要類似的高優先級 goroutine。

所以有公司直接在 runtime 提供了接口,讓用戶可以通過接口來創建特殊優先級的 goroutine。

除了暴露接口外,對 runtime 的實現代碼也是要做不少修改的。

通過 SSA 進行的靜態檢查

我們知道,當前社區的 golangci-lint 大多是用 Go 內置的編譯前端來完成的,在編譯後的 ast 上做一些邏輯,來提示用戶代碼中可能存在的問題。

在一些較底層的編程場景,希望能夠消滅所有的堆分配,所以他們通過檢查生成的 SSA 中是否有 newobject 的調用來輔助進行代碼的優化。

垃圾回收

Go 語言的垃圾回收沒有分代,分代會涉及到不同代際之間的對象移動,從 Go 官方歷史上的分享來看,Go 的開發者們對 non-moving 比較執著。因爲如果堆上對象會 move 的話,需要在讀對象時開啓 read barrier,幾乎所有場景都是讀多寫少的場景,這樣會極大影響程序性能,所以官方現在在分代的研發上處於停滯狀態。

國內某公司在之前官方分代 GC CL 的基礎上實現了分代垃圾回收,不過因爲看不到代碼,不太清楚他們最終在生產環境是否能夠達到較好的性能改善。

總結

未來如果發現更多值得一聊的優化的話,也許會寫個續。

本篇中的內容都是簡單的介紹,沒有太多細節,如果感興趣的讀者比較多的話,我們後續把每一點都展開來講講~

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/X7OU9JjSThB5IZF_KVT1Jg