前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[Golang]包管理

[Golang]包管理

作者头像
别打名名
发布于 2020-07-28 07:26:35
发布于 2020-07-28 07:26:35
1.7K00
代码可运行
举报
文章被收录于专栏:小白AI.易名小白AI.易名
运行总次数:0
代码可运行
  • 1 GOPATH vs Go Modules
  • 2 Go Modules、Go Module Proxy 和 goproxy.cn
  • 3 Go Modules 相关知识
    • 3.1 语义化版本控制规范
    • 3.2 go.mod
    • 3.3 go.sum
    • 3.4 GOPROXY、GONOPROXY、GOSUMDB、GONOSUMDB、GOPRIVATE
  • 4 Go Modules 及其相关常用命令
  • 5 Go Modules 实践
    • 5.1 创建一个 Go Modules 项目
    • 5.2 本地包依赖管理
    • 5.3 如何发布我们的模块呢?
    • 5.4 迁移到 Go Modules 包管理
  • 6 总结
  • 7 参考资料

本文是本人在探索 Go 最新的包管理 Go Modules 的一些总结,希望能够更深入了解 Go 最新的包管理方式,以及在实际环境中将它很好的使用起来。

1 GOPATH vs Go Modules

Go1.5 之前用 GOPATH 以及 GOROOT 这两个环境变量来管理包的位置,GOROOTGo 的安装目录,以及编译过程中使用到的系统库存放位置,如fmt。Go1.5Go1.7 开始稳定到 Vendor 方式,即依赖包需要放到 $GOPATH/src/vendor 目录下,这样每个项目都有自己的 vendor 目录,但是如果依赖同样的三方包,很容易造成资源重复,Go vendor 出现了几种主流的管理工具,包括 godepgovendorgolide等。

Go1.11 之前,GOPATH 是开发时的工作目录,其中包含三个子目录:

  • src目录:存放go项目源码和依赖源码,包括使用 go get 下载的包
  • bin目录:通过使用 go install 命令将 go build 编译出的二进制可执行文件存放于此
  • pkg目录:go源码包编译生成的lib文件存储的地方

Go1.11 之前,import 包时的搜索路径

  • GOROOT/src: 该目录保存了Go标准库代码(首先搜寻导入包的地方)
  • GOPATH/src: 该目录保存了应用自身的各个包代码和第三方依赖的代码
  • ./vendor :vendor 方式第三方依赖包(如果支持Vendor)

Unix 和类 Unix 系统上,GOPATH 默认值是 $HOME/go,Go1.11 版本后,开启 GO Modules 后,GOPATH的作用仅仅为存放依赖的目录了。

Go1.11 版本之前,GOPATH 是必需的,且所有的 Go 项目代码都要保存在 GOPATH/src 目录下,也就是如果想引用本地的包,你需要将包放在 $GOPATH/src 目录下才能找得到。Go1.11 版本之后,GO 官方引入了 Go Modules,不仅仅方便的使用我们的依赖,而且还对依赖的版本进行了管理。

在Go1.11后通过 go mod vendor-mod=vendor来实现 Vendor 管理依赖方式。本来在 vgo 项目(Go Modules前身)是要完全放弃 vendor,但是在社区反馈下还是保留了。总之就是在 Go.1.11 之后需要开启 Go Modules 条件下才能使用 Vendor,具体地感兴趣或还沿用了 Vendor 的朋友可以去了解下,不过建议以后仅使用 Go Modules 包管理方式了。

2 Go Modules、Go Module Proxy 和 goproxy.cn

Go ModulesGo 1.11 推出的功能模块,前身是 vgo,成长于 Go 1.12,丰富于 Go 1.13 是 Go 更好的一种模块依赖管理解决方案实现。

Go Module Proxy 是随着 Go Modules 一起产生的模块代理协议,通过这个协议,我们可以实现 Go 模块代理,通过镜像网站下载相关依赖模块。

proxy.golang.orgGo 官方模块代理网站,不翻墙中国用户是无法访问的,而 goproxy.cn (官方推荐是使用 Go1.13 或以上版本)是七牛云推出的非盈利性 Go 模块代理网站,为中国和世界上其他地方的 Gopher 们提供一个免费的、可靠的、持续在线的且经过 CDN 加速的模块代理,添加这个代理很简单:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 开启 GO Modules 包管理方式
$ go env -w GO111MODULE=on
# 设置代理为 https://goproxy.cn
# 你也可以设置多个代理,通过逗号分隔开,模块从左至右设置的代理中查找获取
$ go env -w GOPROXY=https://goproxy.cn,direct

“注意:模块可能是一个项目,项目下面可以包含很多包。

3 Go Modules 相关知识

3.1 语义化版本控制规范

Go Modules 是如何实现版本控制的呢?通过强制使用语义化版本控制规范,详见 https://semver.org/lang/zh-CN/ 示例,即我们发布版本的时候必须按照官方指定的版本命名格式来发布,具体的:

  • 你的版本 Tag 没有遵循语义化版本控制规范那么它就会忽略你的 Tag,然后根据你的 Commit 时间和哈希值再为你生成一个假定的符合语义化版本控制规范的版本号,比如v0.0.1-20180523231146-b3f5c0f6e5f1
    • 如v0.1.0,v1.0.0,v1.5.0-rc.1,v 这个字符是必须的
  • Go Modules 默认认为,只要你的主版本号不变,那这个模块版本肯定就不包含重大变更,则我们 import 的时候 path 不会受到影响,比如 v1.0.0v2.0.0,就是一个重大版本变更,在编写代码 import 模块的时候,v1版本的包名是github.com/xx/xx,v2版本的包名就是github.com/xx/xx/v2了,在我们使用go get的时候也需要带上完整的版本路径才能导入指定的版本。

3.2 go.mod

一个模块是通过go.mod来定义的,也是标志该项目是否启用了 Go Modules,如果存在该文件,默认则启动 Go Modules,除非你设置 GO111MODULE=off。该文件描述了该模块的依赖、不依赖、依赖替换、当前模块名称(路径)、所要求的Go版本信息,示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module my/thing
go 1.12
require other/thing v1.0.2
require new/thing/v2 v2.3.4

// 注释:也可以用块结构设定多个依赖模块
require (
	new/thing v2.3.4
	old/thing v1.2.3
	github.com/my/repo v0.0.1-20180523231146-b3f5c0f6e5f1
)
exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5

其中:

  • module, 定义模块的路径(名称)
  • go, 设置期望的Go版本
  • require, 在给定的版本或者更高的版本模块中,指定依赖一个特定版本
  • exclude, 排除特定模块版本依赖
  • replace, 将指定模块版本替换为其他模块版本

requirereplace 仅仅在主模块的 go.mod 中应用,在依赖模块的 go.mod 中的 require 和 replace 将会忽略。另// indirect,表示非直接依赖。go buildgo getgo installgo listgo testgo mod tidygo mod why 这些命令会去检测本地模块的引用和存在,如果不存在会去下载相应模块,然后更新记录到 go.mod 文件。

replace 具体的作用就是将一个模块版本替换为另一个模块版本, => 标志前是待替换版本。

3.3 go.sum

go.sum 文件的作用是为了验证每个下载的模块是否与过去下载的模块匹配,并检测模块是否被恶意篡改。比如你在开发过程中依赖了一个模块的某个版本,完成开发后,你上层版本管理平台时只有go.modgo.sum,如果其他人去使用该项目或者基于该项目开发,则需要在他本地重新下载相应的模块,这时go.sum里记录的加密校验和就可以校验新环境下下载的模块是否与原始依赖保持一致。

在每一个模块的根目录都有一个go.sumgo.mod相匹配,记录go.mod中每一个依赖模块的加密校验和,校验和的前缀是h<N>,h1表示采用SHA-256算法得到校验和,go.sum的每一行格式为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<模块路径> <版本>[/go.mod] <校验和>
// 示例:
// cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
// github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
// golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=

如果下载的模块没有包含在 go.sum 中,而且是一个公共可获得的模块,Go 命令会去 Go 校验数据库(如默认配置的 sum.golang.org 或中国大陆官方校验和数据库 sum.golang.google.cn )查询并获取该模块的校验和,如果下载的模块代码与校验和不匹配,则报告不匹配相关信息并退出,如果匹配,则将校验和写入 go.sum文件中。

3.4 GOPROXY、GONOPROXY、GOSUMDB、GONOSUMDB、GOPRIVATE

Go 命令可以根据 GOPROXY 环境变量的设置,从代理获取模块或直接连接到源代码管理服务器GOPROXY 的默认设置是 https://proxy.golang.org,direct,这意味着尝试获取 Go 模块镜像,如果代理报告它没有该模块(HTTP错误404或410),则返回直接连接。如果 GOPROXY 设置为 "direct" 字符串,则直接连接到源代码管理服务器下载模块。将 GOPROXY 设置为 "off" 不允许从任何源下载模块。你也可以设置多个代理,通过逗号(,) 或者管道符号(|)分隔开,模块从左至右设置的代理中查找获取,直到获取模块成功或失败返回。

通过设置 GOSUMDB 环境变量,可以配置模块校验数据库,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GOSUMDB="sum.golang.org"                                        # 默认配置,URL 默认都是 https://,后跟数据库地址
GOSUNDB="sum.golang.google.cn"                                  # 中国大陆可访问
GOSUMDB="sum.golang.org+<publickey>"                            # 使用除了sum.golang.org 和 sum.golang.google.cn 域名外其他需要给出公钥
GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"     #
GOSUMDB="off"                                                   # 关闭校验,任何模块可以被使用

Go 命令默认是从公共的镜像下载代理网站 proxy.golang.org 下载代码,然后通过公共校验和数据库 sum.golang.org 获取模块校验和实现校验,但是有时候公司需要实现私有化依赖,即可以控制哪些模块可以不使用公共代理或校验数据库。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 任何匹配*.corp.example.com为前缀的模块都被视为私有模块,包括如git.crop.example.com/xxx, rsc.io/private/yyy
# 配置GORPIVATE过滤规则时,通过逗号分隔配置多个匹配路径
$ go env -w GOPRIVATE=*.corp.example.com,rsc.io/private

为了对模块的下载和校验进行细粒度的控制,GONOPROXYGONOSUMDB 环境变量也支持同 GOPRIVATE 同样的列表设置方式,也是配置统配模块或者指定模块,从而覆盖 GOPRIVATE 对相关模块的作用,如果 GONOPROXY 设置成 none,则所有的模型(公有,私有)都将从 GOPROXY 代理上下载,即 GOPRIVATE 设置无法生效。如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GOPRIVATE=*.corp.example.com
GOPROXY=proxy.example.com
GONOPROXY=none

如果想要将某个模块不从 GOPROXY 中查找下载,则设置 GONOPROXY 即可,并且也不校验该模块,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GOPROXY=https://proxy.golang.org
GONOPROXY=gitlab.com/xxx
GONOSUMDB=$GONOPROXY

如果想禁止从 GOPROXY 上查找下载模块,则可以配置 GONOPROXY=* 或者 GOPROXY=off,不过这样设置不会关掉对模块的校验。

“注:GOPRIVATE 、GONOSUMDB、GONOPROXY 的通配配置规则同Linux glob通配符语法一致,如 * 表示匹配任意长度任意字符串。

4 Go Modules 及其相关常用命令

  • go get 命令会下载给定的导入模块路径所有的包,包括包的依赖模块
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号,  y是次要版本号)
$ go get -u [URL]
# 将会升级到最新的次要版本
$ go get -u=patch [URL]
# 将不会校验校验码,同 GOSUMDB=off 效果一致;另外可以下载来自非https域名的模块
$ go get -insecure [URL]
# 下载指定版本的模块,如最新版本是v2.2.0,将级下载v2.1.0
$ go get github.com/urfave/cli/v2@v2.1.0
# 拉取master分支最新提交
$ go get github.com/my/repo@master
# 拉取某个指定的提交
$ go get github.com/my/repo@772611b
  • go list -m all : 查看在编译过程使用到所有直接和间接依赖项的最终版本
  • go list -m -u all : 查看在编译过程使用到所有直接和间接依赖项的最终版本以及他们可升级的次要的(minor)或补丁(patch)版本
  • go get -u ./...go get -u=patch ./...: 在模块根目录执行,将所有直接和间接依赖项更新为最新的次要(minor)或补丁(patch)版本
  • go build ./...go test ./... : 在模块根目录执行,编译或测试模块中的所有包
  • go clean -modcache :删除下载的缓存内容,默认目录为$HOME/go/mod,整个目录会删除掉

“注:如果没有 go.mod 文件,go get下载依赖后不会将版本依赖信息记录到 go.mod 中。

go mod 相关:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go mod download    下载依赖的module到本地cache
$ go mod edit        编辑go.mod文件
$ go mod graph       打印模块依赖图
$ go mod init        在当前文件夹下初始化一个新的module, 创建go.mod文件
$ go mod tidy        增加丢失的module,去掉未用的module
$ go mod vendor      将依赖复制到vendor目录下
$ go mod verify      校验依赖
$ go mod why         解释为什么需要依赖

具体使用:

  • $ go mod download [-x] [-json] [modules]
    • 默认下载主模块依赖的所有模块到本地缓存目录中(默认为$HOME/go/pkg/mod/cache)
    • -x 打印下载过程中执行的命令
    • -json 将一系列json对象打印到标准输出,描述每个下载的模块信息,包括是否失败、版本、模块路径、校验和值等
  • $ go mod verify
    • 验证检查当前模块(存储在本地下载的源缓存中)的依赖项在下载后是否未被修改。如果所有模块都未修改,verify会打印“all modules virfied”,否则它会报告哪些模块已更改,并导致“go mod”以非零状态退出
  • $ go mod edit [editing flags] [go.mod]
    • 主要是在命令行操作编辑go.mod文件
    • -fmt 标志表示格式化 go.mod 文件,不做除此之外其他更改操作
    • -module=new-module-path 标志 : 更改主模块的路径(项目名称),即第一行的 module 内容
    • -require=path@version-droprequire=path :添加和删除require()内容,但一般添加依赖我们更常用 go get 将依赖自动更新到 go.mod
    • -exclude=path@version-dropexclude=path@version:添加和删除exclude 内容,如果以及添加已经存在,则不做任何操作。
    • -replace=old[@v]=new[@v] : 将旧模块替换为新模块
    • -go=version : 设置预期的Go语言版本
    • -print : 按格式化打印 go.mod 内容,不对 go.mod 做任何修改
    • -json : 按json格式打印 go.mod内容,如果需要知道项目的所以依赖用 go list -m -json all
  • $ go mod graph
    • 打印所有模块的依赖关系,除了主模块,其他模块依赖关系都带有具体版本信息
  • $ go mod init [module]
    • 在当前目录下创建一个模块路径(模块名)为 [moudle]go.mod,如果已经存在,则提示已经存在。
  • $ go mod tidy [-v]
    • 确保 go.mod 与 源代码匹配,会添加当前编译过程中包或者其他依赖所缺少的模块,会删除没有提供任何包无用的模块,还会添加一些缺失的校验信息到 go.sum中,移除无用的校验信息
    • -v 标志将 tidy 过程中已删除(没有使用到)的模块信息打印到标准错误
  • $ go mod vendor [-v]
    • 这个命令是重置我们主模块vendor目录,将所以编译和测试依赖的包(不包括测试代码)全部拷贝一份到vendor目录。
    • -v 标志打印执行命令过程被拷贝的模块和包的名称到标准错误
  • $ go mod why [-m] [-vendor] packages
    • 显示出 go mod graph 依赖关系中的一个最短依赖关系,比如 go mod graph 展示出主模块依赖子模块1,子模块1依赖子模块2,则会全部展示,而如果想查某个模块或某些模块依赖了哪些,则可以用 go mod why

5 Go Modules 实践

5.1 创建一个 Go Modules 项目

Go 官方 FAQs 上提到我们的项目没有任何模块依赖是否有必要去添加一个 go.mod 文件呢?它的建议是有必要的,这可以让我们不再依赖 GOPATH环境变量,也有利于模块的生态系统发展和交流,另外也可以作为你项目的一个声明标志,不过一切都是基于在 GO1.11 版本之上。那如何创建一个 Go Modules 项目呢?

  • 首先我们要求 Go1.11 版本或以上,建议使用 Go 1.13 版本或以上
  • 进入我们项目的根目录
    • $ cd <project path>
  • 我们无需设置 GO111MODULE 环境变量,执行
    • go mod init [your module path],如 go mod init github.com/my/repo 、
  • 然后就可以编写代码,进行编译了,hello.go
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
  • 编译$ go build -o hello.go
  • 执行 $ ./hello
  • $ cat go.mod
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module githu.com/my/repo

go 1.14

require rsc.io/quote v1.5.2

5.2 本地包依赖管理

Go Modules 没有出来之前,在项目中 import 本地其他包都是通过设置好 GOPATH,将项目路径加入到 GOPATH环境变量中,然后将我们的包放入 $GOPATH/src 下,这样我们就可以找到本地依赖包。比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- {your project path}
    - bin
    - pkg
    - src
        - {package1 name}        # 包名文件夹必须与包名一致
            - package files
        - {package2 name}
            - package files
        - main
            - main.go

如何用 Go Modules 去实现本地包依赖呢?

在上一节,创建了一个最简单的 Go Modules 项目,我们依赖了 rsc.io/quote 模块,这是一个从公共镜像代理上可获得的模块,但是如果我们自己定了内部的包,这个时候采用 Go Modules 方式如何去找到我们的包呢?比如 pkg1 和 pkg2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.
├── bin
├── cmd
│   └── hello
│       └── hello.go
├── go.mod
├── go.sum
├── pkg1
│   ├── pkg1_src.go
│   └── pkg1_test.go
└── pkg2
    └── pkg2_src.go

其中 hello.go 、pkg1_src.go 、pkg1_test.go和 pkg2_src.go 内容分别为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
    "rsc.io/quote"
    "github.com/my/repo/pkg1"
)

func main() {
    fmt.Println(quote.Hello())
    pkg1.HelloPkg1()
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package pkg1                                                                    
                                                                                
import (                                                                        
    "fmt"                                                                       
)                                                                               
                                                                                
func HelloPkg1() string {                                                                                                        
    fmt.Println("Hello pkg1")                                                   
    return "Hello pkg1"                                                         
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package pkg1                                                                                                                     
                                                                                
import "testing"                                                                
                                                                                
func TestHello(t *testing.T) {                                                  
    want := "Hello pkg1"                                                        
    if got := HelloPkg1(); got != want {                                        
        t.Errorf("Hello() = %q, want %q", got, want)                            
    }                                                                           
}     
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package pkg2

import (
        "fmt"
)

func HelloPkg2() {
        fmt.Println("Hello pgk2")
}

通过在 hello.go 中使用我们的项目模块路径 + 具体包路径就可以引用到我们需要的本地包了。然后在项目根目录编译,将可执行文件输出到 bin 目录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 在项目根目录中编译,./... 模式表示匹配在当前模块中所有的packages
# 注意:采用 ./... -o 只指定目录,不能指定具体的生成对象名称,因为你可能有多个可执行文件一起生成
$ go build -o bin ./...

# 也可以单独编译我们的可执行文件,并指定生成名称
$ go build -o bin/hello_rename cmd/hello/hello.go

bin 目录下默认生成 hello 名称的可执行文件,执行 ./bin/hello:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Ahoy, world!
Hello pgk1

你也可以单独将某个包编译成 Go 静态库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 单独编译某个包,同样的要找到这个包也需要使用项目模块路径 + 具体包路径
$ go build -buildmode=archive -o bin/libpkg1.a github.com/my/repo/pkg1

5.3 如何发布我们的模块呢?

在完成我们 Go 模块后,如果需要提供给别人使用就需要发布版本,结合版本控制系统(VCS),只要遵循 Go 的语义化版本控制规范,就可以很方便的发布版本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 【step1】在发布之前,建议执行 tidy,清除掉无关或者我们使用到但尚未添加进来的模块
$ go mod tidy
# 【step2】测试本项目模块中所有测试样例,确保测试成功,go test all 会测试依赖在内的所有测试样例
$ go test ./...

# 确保 go.sum 和 go.mod 文件都一起提交到该版本中,go.sum 不是类似 nodejs 的 package-local.json 锁文件,更多地它可以帮助校验本地下载地模块是否被篡改
# 【step3】版本提交
# git 提交操作,发布v1.0.0版本
$ git add -A
$ git commit -m "hello: changes for v1.0.0"
$ git tag v1.0.0
$ git push origin v1.0.0

在 Go 版本发布中,模块导入路径默认是省略了 v0、v1 主版本的。至于为什么这样设计,可以参考:https://github.com/golang/go/issues/24301 。

如果要发布 v2 或者更高的版本?在官方的 FAQ 中很详细的介绍了操作和一些建议,比如你有一个版本仓库,已经打上了 v2.0.0 的标记,但是你还没有采用 Go Modules 方式,建议你后续直接打上 v3,从而很清晰的而区分采用了 Go Modules 方式的版本。下面以发布一个 v2+ 版本其中一种方式(另外参见 https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher )作为示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 【step1】 将你的模块路径带上v2+信息,如
$ go mod edit -module github.com/my/repo/v2
# 【step2】 更新你项目中使用了其他本地包的模块路径,都加上v2,如我们上面的hello.go,则变为github.com/my/repo/v2/pkg1
# 【step3】 版本控制发布 v2.x.x tag

5.4 迁移到 Go Modules 包管理

很多 Go 项目使用以前的老的包管理方式,Go 在迁移方面也做了很多工作,包括从以前的依赖管理自动迁移到 Go Modules 方式以及诸多迁移注意事项。这里就不展开了,具体参见 https://github.com/golang/go/wiki/Modules#migrating-to-modules 。

当然,最简单的迁移方式就是使用 Go1.13 或以上版本,重新组织你的项目和依赖,以及所有的导入包路径的修改,这相当于新初始化一个 Go Modules 项目。

6 总结

从最早的 GOPATHVendor,再到 vgo 的出现, 最终 Go Modules 成熟,Go 的包依赖管理有了一个很大的进步,尤其是版本、资源和模块权限的管理。Go Modules 还有更多的使用细节,这里没有去校验,如果文章中有什么理解错误,欢迎 Gopher 指正。

7 参考资料

golang.google.cngolang.org 可替换,内容一致。golang.google.cn 在中国大陆无需翻墙即可访问。

  • https://stackoverflow.com/questions/37237036/how-should-i-use-vendor-in-go-1-6
  • https://github.com/golang/go/wiki/Modules#how-do-i-use-vendoring-with-modules-is-vendoring-going-away
  • https://tip.golang.org/cmd/go/#hdr-Modules_and_vendoring
  • https://devopscon.io/blog/go-1-11-new-modules/
  • https://developpaper.com/golang-1-5-to-golang-1-12-package-management-golang-vendor-to-go-mod/
  • https://github.com/golang/go/wiki/Modules
  • https://goproxy.cn/#Usage
  • https://github.com/goproxy/goproxy.cn/blob/master/README.zh-CN.md
  • https://github.com/golang/go/wiki/Modules#is-gosum-a-lock-file-why-does-gosum-include-information-for-module-versions-i-am-no-longer-using
  • https://davidchan0519.github.io/2019/04/05/go-buildmode-c/
  • https://github.com/go-modules-by-example/index/blob/master/009_submodules/README.md
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 别打名名 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Redis - 适配全国产操作系统的那些坑
github: https://github.com/jemalloc/jemalloc
小小工匠
2021/08/17
1.8K0
一次性能优化经历
自从上次修改backlog之后, Silly的IO能力,就一直以少量(约4~6K)的差距落后于redis,却一直找不到原因。
重归混沌
2020/04/26
3890
内存泄漏的定位与排查:Heap Profiling 原理解析
系统长时间运行之后,可用内存越来越少,甚至导致了某些服务失败,这就是典型的内存泄漏问题。这类问题通常难以预测,也很难通过静态代码梳理的方式定位。Heap Profiling 就是帮助我们解决此类问题的。
PingCAP
2021/11/18
1.8K0
MySQL替换默认内存分配器为tcmalloc
背景: 生产上发现有套MySQL实例的内存占有率一直在涨,这台机器日常只有连接(查询、修改数据)
保持热爱奔赴山海
2023/10/11
5770
Redis源码解析——前言
        今天开启Redis源码的阅读之旅。对于一些没有接触过开源代码分析的同学来说,可能这是一件很麻烦的事。但是我总觉得做一件事,不管有多大多难,我们首先要在战略上蔑视它,但是要在战术上重视它。除了一些高大上的技术,我们一般人都能用比较简单的方式描述它是干什么的。比如Redis,它不就是一个可以通过网络访问的KV型数据库嘛。在没有源码的情况下,可以想象出它应该是通过网络服务、指令解析、特殊的内存结构设计(方便增删改查)、持久化等技术构成。然后我们在战术上要重视它各个技术的实现,特别是一些我们没想到的一些技术。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
7330
Redis源码解析——内存管理
        在《Redis源码解析——源码工程结构》一文中,我们介绍了Redis可能会根据环境或用户指定选择不同的内存管理库。在linux系统中,Redis默认使用jemalloc库。当然用户可以指定使用tcmalloc或者libc的原生内存管理库。本文介绍的内容是在这些库的基础上,Redis封装的功能。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
1.1K0
故障分析 | MySQL 全文索引触发 OOM 一例
作者:付祥,现居珠海,主要负责 Oracle、MySQL、mongoDB 和 Redis 维护工作。
爱可生开源社区
2024/01/17
2820
故障分析 | MySQL 全文索引触发 OOM 一例
Linux进程内存管理(一)
Linux 环境下,进程的内存管理器默认是使用 glibc 实现的 ptmalloc 。另外,还有两个比较有名的内存管理器:google 的 tcmalloc 和
linjinhe
2018/06/06
3.7K0
redis 源代码分析(一) 内存管理
redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中统一使用zmalloc,zfree一系列函数,其相应的源代码在src/zmalloc.h和src/zmalloc.c两个文件里,源代码点这里。
全栈程序员站长
2022/07/12
4150
ptmalloc、tcmalloc与jemalloc对比分析
在开发微信看一看期间,为了进行耗时优化,基础库这层按照惯例使用tcmalloc替代glibc标配的ptmalloc做优化,CPU消耗和耗时确实有所降低。但在晚上高峰时期,在CPU刚刚超过50%之后却出现了指数上升,服务在几分钟之内不可用。最终定位到是tcmalloc在内存分配的时候使用自旋锁,在锁冲突严重的时候导致CPU飙升。为了弄清楚tcmalloc到底做了什么,仔细了解各种内存管理库迫在眉睫。
233333
2024/02/23
2K0
ptmalloc、tcmalloc与jemalloc对比分析
tcmalloc
TCMalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替代系统的内存分配相关的函数(malloc、free,new,new[]等)。
golangLeetcode
2022/08/02
1.8K0
tcmalloc
深入浅出理解DeepSeek 3FS (3) 步步引导轻松理解内存管理,面试必看
工作8年的小王 同学 为了准备c++面试, 很早 就从脉脉上搜索过类似题目,信心满满而去, 什么返回值区别,重载区别?还有函数用法区别?
早起的鸟儿有虫吃
2025/04/11
930
深入浅出理解DeepSeek 3FS (3) 步步引导轻松理解内存管理,面试必看
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第三天:MakeFile
配套资料: makefile方面有陈皓大神的跟我一起写MakeFile,我就不班门弄斧了。
看、未来
2020/08/31
7680
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第二天:空间配置(zmalloc)
为了大家看文中那一堆的“#”不至于晕掉,建议先看一下这篇:讲通C/C++预编译/条件编译指令 #ifdef,#ifndef,#endif,#define,…
看、未来
2020/08/31
7030
探秘VPP:快速定位libc内存泄漏的有效方法
这里就使用到了动态库预加载LD_PRELOAD机制。LD_PRELOAD 是 Linux 系统中一个非常强大的特性,它允许用户通过环境变量指定在加载其他共享库之前优先加载的共享库。这一机制主要用于动态链接阶段,可以在不修改程序源代码的情况下改变或增强程序的行为。
dpdk-vpp源码解读
2025/03/14
1090
探秘VPP:快速定位libc内存泄漏的有效方法
技术分享 | MySQL 内存管理初探
本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
爱可生开源社区
2020/10/22
2.8K0
技术分享 | MySQL 内存管理初探
频繁分配释放内存导致的性能问题的分析
1 压力测试过程中,发现被测对象性能不够理想,具体表现为: 进程的系统态CPU消耗20,用户态CPU消耗10,系统idle大约70 2 用ps -o majflt,minflt -C program命令查看(pidstat也可以),
早起的鸟儿有虫吃
2019/05/05
7.1K0
频繁分配释放内存导致的性能问题的分析
Redis内存碎片:深度解析与优化策略
在我们探究和优化Redis性能的过程中,「Redis内存碎片」是一个不可忽视的话题。
BookSea
2023/10/16
7750
Redis内存碎片:深度解析与优化策略
ptmalloc,tcmalloc和jemalloc内存分配策略研究
最近看了glibc的ptmaoolc,Goolge的tcmalloc和jemalloc,顺便做了一点记录。可能有些地方理解地不太对,如有发现还请大神指出。
owent
2018/08/01
10.9K0
ptmalloc,tcmalloc和jemalloc内存分配策略研究
gpreftools动态追踪Nginx进行性能分析
之前介绍了多种nginx调试工具,今天介绍nginx性能分析工具——gperftools
李俊鹏
2020/06/12
1.7K0
gpreftools动态追踪Nginx进行性能分析
推荐阅读
相关推荐
Redis - 适配全国产操作系统的那些坑
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 1 GOPATH vs Go Modules
  • 2 Go Modules、Go Module Proxy 和 goproxy.cn
  • 3 Go Modules 相关知识
    • 3.1 语义化版本控制规范
    • 3.2 go.mod
    • 3.3 go.sum
    • 3.4 GOPROXY、GONOPROXY、GOSUMDB、GONOSUMDB、GOPRIVATE
  • 4 Go Modules 及其相关常用命令
  • 5 Go Modules 实践
    • 5.1 创建一个 Go Modules 项目
    • 5.2 本地包依赖管理
    • 5.3 如何发布我们的模块呢?
    • 5.4 迁移到 Go Modules 包管理
  • 6 总结
  • 7 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档