01 背景html
近日騰訊正式對外發布 2020 年度《騰訊研發大數據報告》,這份由騰訊技術委員會出品的報告,披露了過去一年騰訊在研發投入、研發效能及開源協同等方面的重要數據。C++ 蟬聯騰訊最受歡迎的編程語言。隨着雲計算和微服務相關技術的進一步發展,Go語言使用次數增速第一,並超越 JavaScript 成爲騰訊第二受歡迎的編程語言。基於如此巨大的 Go 開發者基數,內部開發體驗就顯得尤其重要。git
可是長久以來 Go 的版本管理確實是你們開發中遇到最頭疼的問題,在 GOPATH 模式中,咱們將所需依賴代碼拉取到 GOPATH/src 中,這樣在編譯過程當中,Go 會去 GOPATH 中根據 import path 尋找響應的代碼庫。可是若是咱們從新拉取了最新的代碼或者本身修改了這個依賴已有的代碼,整個編譯過程不會察覺到這些變動,可能會形成編譯失敗或者線上故障,因而從 Go 1.11 起,Go 官方引入了 Go Modules 來解決版本管理的問題,用一句話解釋什麼是 Go Modules 那就是:github
Modules are how Go manages dependencies.golang
Go Modules 是一種分散式設計,儘管有不少諸如 goproxy.io 這樣的公共服務,可是 Go Modules 設計中沒有一個公開的註冊中心,模塊做者能夠在代碼倉庫中建立版本標籤來發布新版本。編程
$ git tag v1.2.3 $ git push --tags
其餘開發者就能夠馬上下載這個版本了瀏覽器
$ go get -d example.com/mod@v1.2.3
02 使用 GOPROXY緩存
咱們建議默認配置使用 GOPROXY 來獲取依賴模塊,緣由有下面幾個:
2.1安全
企業內部證書問題收斂服務器
不少公司內的證書都是本身簽發的,在各個操做系統、瀏覽器、工具中都不被信任,這給內部的開發者帶來了額外的配置負擔,他們在使用各類工具時,須要強行去信任這個內部簽發的證書,咱們能夠再 goproxy server 這一層作同一信任配置,這樣衆多開發者就無需再進行額外操做。markdown
2.2
海外資源可用性高
諸如 golang.org/x 相似的一些經常使用的包託管於谷歌服務器上,咱們須要用到 proxy 幫咱們進行獲取,這裏就不展開了。
2.3
模塊拉取速度快
有些人說只有海外資源纔有加速的需求,其實不是這樣的,即便是內網的代碼依賴模塊,若是你使用 proxy 也比直接拉取快不少,接下來咱們分析下緣由。
Go 能夠經過 HTTP 協議經過 proxy 下載依賴模塊,這要比直接從源代碼庫中拉取快 5 到 20 倍。GOPROXY 的協議是無狀態的,它的設計很是簡單以至於咱們可使用一個靜態的文件服務來實現它。Go 內部在實現的時候也支持file:// 協議,這樣避免了好比在測試場景中獲取依賴時產生對網絡的依賴,能夠直接使用一個本地文件系統做爲 proxy 服務。下圖是咱們使用騰訊名字服務項目(北極星)進行的一項拉取測試。
使用 goproxy 下載之因此如此之快追究其緣由有下面幾個:
下降了對源代碼託管服務(Git)的依賴性
若是有一天公司內部的 gitlab 或者外部的 github 服務臨時不可用了,雖然咱們沒法提交發布新版本了,可是若是proxy 緩存了你以前的依賴模塊,咱們已有的編譯將不會受到影響, CI/CD 也不會失敗。甚至有些源碼倉庫被刪除了,咱們還能夠繼續進行編譯。
2.5
fallback 機制
若是用戶配置的 goproxy 服務不可用了怎麼辦?好在 Go 支持配置逗號或者管道分隔的 goproxy 列表,若是第一個服務器返回了 404 或者 410,甚至是不可用(超時),Go 能夠根據用戶的配置嘗試使用其餘 goproxy 服務或者直接使用本地直接獲取的方式。這種 fallback 機制使得 Go 不依賴於某一個 goproxy 服務的可用性。
2.6
更加安全可控
使用公司內部的 goproxy 能夠防止公司內部開發人員配置不當形成項目中 import path 泄露到公網中,避免給一些敏感業務和項目帶來沒必要要的損失和麻煩。
03 Goproxy For Tencent
既然使用 goproxy 服務有這麼多的好處,那麼爲騰訊內部提供一個穩定的 goproxy 服務勢在必行了,並且不少團隊的呼聲也很是高。惋惜谷歌實現的 proxy 不是開源的,因而咱們使用了goproxy.io 開源項目。首先確保要運行的服務器是已經安裝了 go 命令,goproxy 項目是開源的,用 go 語言開發,使用 Go modules 能夠很方便的進行編譯:
git clone https://github.com/goproxyio/goproxy.git cd goproxy make
編譯好的文件位置是 ./bin/goproxy , 使用 ./bin/goproxy -h 查看參數使用說明:
Usage of ./bin/goproxy: -cacheDir string go modules cache dir [指定 Go 模塊的緩存目錄] -exclude string exclude host pattern [proxy 模式下指定哪些 path 不通過上游服務器] -listen string service listen address [服務監聽端口,默認 8081] -proxy string next hop proxy for go modules [指定上游 proxy server,推薦 goproxy.io]
因爲咱們還須要加速內網代碼模塊,因此咱們使用 router 模式:
direct +----------------------------------> internal repos | match|pattern | +---+---+ +----------+ go get +-------> |goproxy| +-------> |goproxy.io| +---> golang.org/x/net +-------+ +----------+ router mode proxy mode
使用下面命令行啓動服務:
./bin/goproxy -listen=0.0.0.0:80 -cacheDir=/data/modules -proxy https://goproxy.io -exclude "git.tencent.com"
配置好環境變量,接下來開發者就能夠從這個服務上拉取代碼了:
export GOPROXY=http://[你的服務器IP]:80 export GOSUMDB=off go get github.com/pkg/errors
這樣用戶能夠經過上面的配置拉取外部公共依賴模塊和內部公共模塊代碼庫,若是要編譯的項目對內部私有代碼庫有依賴怎麼辦呢,還須要配置一個變量:
GOPRIVATE=*.corp.example.com,rsc.io/private
關於這個變量的具體介紹能夠參考:https://goproxy.io/zh/docs/GOPRIVATE-env.html
因爲騰訊內部開發者和 Go 項目衆多,咱們還實現了一個內部的 sumdb 服務,因此即便是騰訊內部代碼倉庫也能夠被記錄哈希值,防止項目依賴模塊從新打標形成錯誤的編譯,從而帶來不可挽回的損失, 同時也保障了編譯項目的源碼安全。最後,因爲這個項目支持 Promethues 監控,接下來把服務指標接入到 Promethues 監控中,而且把架構調整好,騰訊內部 goproxy 服務的架構其實也並不複雜:
總語
Go Modules 的引入確實大大提高了開發者體驗,它解決了 GOPATH 模式下不少解決不了的問題。目前騰訊內部goproxy 服務天天的請求量在百萬級別,它幫助了騰訊雲、騰訊文檔、騰訊新聞、騰訊遊戲等多個 BG 和部門,爲你們的編譯節省了大量的等待時間,提升了內部服務的編譯成功率和開發體驗。