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 和部门,为你们的编译节省了大量的等待时间,提升了内部服务的编译成功率和开发体验。