GO依赖管理 | 青训营笔记

38 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

go依赖管理演进

通过sdk引入

image-20230216103627998.png

GOPATH go项目工作区
Go Vendor

image-20230216103710431.png

image-20230216104003056.png

优先从vender目录下找,没有再找gopath

解决版本问题,保证用v1、v2版本的项目都能构建成功。

image-20230216104241511.png

问题:依赖项目源码,不能很清晰标识版本的概念

image-20230216104300989.png

Go Module

解决同一个库依赖多个版本问题

image-20230216104704142.png

image-20230216104827093.png

(类比Java 的 Maven)

Go Module依赖管理方案

go mod

image-20230216105100523.png

首先模块路径用来标识一个模块,从模块路径可以看出从哪里找到该模块,如果是github前缀则表示可以从Github 仓库找到该模块,依赖包的源代码由github托管,如果项目的子包想被单独引用,则需要通过单独的init go。mod文件进行管理。

下面是依赖的原生sdk版本。

最下面是单元依赖,每个依赖单元用模块路径+版本来唯一标示。

image-20230216105256438.png

gopath和vendor都是 源码副本方式进行的依赖,没有版本规则概念。go module为了放方便版本管理则定义了版本规则

语义化:

MAJOR 大版本,不同版本可不兼容,所以即使是同一个库,MAJOR 版本不同也会被认为是不同的模块

MINOR 版本通常是新增函数或功能,向后兼容

patch 版本一般是修复 bug

commit:

基础版本前缀 和语义化版本一样的

时间戳 (yyyymmddhhmmss), 也就是提交 Commit 的时间

校验码 (abcdefabcdef), 包含 12 位的哈希前缀

(每次提交commit后 Go 都会默认生成一个伪版本号)

关键字:

indirect - 标识 间接依赖

incompatible - 标识 可能不兼容的代码逻辑

主版本2+模块会在模块路径增加/vN后缀,这能让go module按照不同的模块来处理同一个项目不同主版本的依赖(允许不同MAJOR不相互兼容)。由于gomodule是1.11实验性引入,所以这项规则提出之前已经有一些仓库打上了2或者更高版本的tag了,为了兼容这部分仓库,对于没有go.mod文件并且主版本在2或者以上的依赖,会在版本号后加上+incompatible 后缀

前面讲语义化版本提到,对于同一个库的不同的major版本,需要建立不同的pkg目录,用不同的gomod文件管理,如下面仓库为例,V1版本gomod在主目录下,而对于V2版本,则单独简历了V2目录,用另一个gomod文件管理依赖路径,来表明不同major的不兼容性。,那对于有些V2+tag版本的依赖包并未遵循这一定义规则,就会打上incompatible 标志, 增加一个compatile的case

依赖图:

image-20230216111506484.png

注:首先要保证v1.3和v1.4兼容的(同属于v1.2版本,前后兼容)

依赖分发-回源:

image-20230216112153253.png

gomodule的依赖分发,也就是从哪里下载,如何下载的问题~ github是比较常见给的代码托管系统平台,而Go Modules 系统中定义的依赖,最终可以对应到多版本代码管理系统中某一项目的特定提交或版本,这样的话,对于go.mod中定义的依赖,则直接可以从对应仓库中下载指定软件依赖,从而完成依赖分发。 但直接使用版本管理仓库下载依赖,存在多个问题——1.首先无法保证构建确定性:软件作者可以直接代码平台增加/修改/删除 软件版本,导致下次构建使用另外版本的依赖,或者找不到依赖版本。2.无法保证依赖可用性:依赖软件作者可以直接代码平台删除软件,导致依赖不可用;3.大幅增加第三方代码托管平台 压力。

解决-go Proxy

go proxy

image-20230216112505514.png

而go proxy就是解决这些问题的方案,Go Proxy 是一个服务站点,它会缓存源站中的软件内容,缓存的软件版本不会改变,并且在源站软件删除之后依然可用,从而实现了供“immutability稳定”和“available可靠”的依赖分发;使用 Go Proxy 之后,构建时会直接从 Go Proxy 站点拉取依赖。类比项目中,下游无法满足我们上游的需求,建立Proxy/适配器来解决问题。

GOPROXY变量配置:go.mod

image-20230216112842632.png

Go Modules通过GOPROXY环境变量控制如何使用 Go Proxy;GOPROXY是一个 Go Proxy 站点URL列表,可以使用“direct”表示源站(前面站点都没依赖的话,回到第三方代码平台上)。对于示例配置,整体的依赖寻址路径,会优先从proxy1下载依赖,如果proxy1不存在,后下钻proxy2寻找,如果proxy2中不存在则会回源到源站直接下载依赖,缓存到proxy站点中。

和设计缓存模式的场景是一致的(本地缓存-分布缓存-最终依赖DB)

工具

go get

image-20230216113821694.png

go mod

image-20230216113848169.png

尽量提交之前执行下go tidy,减少构建时无效依赖包的拉取