最近几个月,或者最近一年,使用etcd做开发的朋友,如果你开启了go module的功能的话,没有出现翻车的现象吗?或者go get -u .更新一下项目依赖试试看。

因为我使用visual studio code的方式是打开整个GOPATH路径,而gopls对于整个GOPATH并不友好,非常的慢,所以我设置了全局变量GO111MODULE=off,还是采用传统的老的库依赖方式。

但是我并不排斥使用go module,并且觉得它对解决库依赖的冲突至关重要,所以我一般在项目中也会是不是的开启go module,更新一下go.mod。但是目前看来go module的推广起来问题还是重重,主要包括下面几个原因:

  1. go module本身的bug

  2. 使用go module的项目使用方式有问题

  3. 一些库没有采用go module

由于go module的一些bug,以及开源项目使用go module的错误姿势,go module模式下导致使用一些代码库困难重重。我们以etcd为例,看看目前使用etcd的翻车现场。

翻车例子

假如看了很多go module的励志文章,信心满满,准备使用etcd开发一些分布式的应用。很显然,相对于zookeeper在java生态圈的地位,在Go生态圈我们自然会选择etcd去做开发。

那么现在第一步,我们创建一个文件夹,生成go module文件:

123
➜  workspace mkdir abc && cd abc➜  abc go mod init  example.com/mgo: creating new go.mod: module example.com/m

加入etcd库:

1234567891011121314151617
➜  abc go get -u -v go.etcd.io/etcdgo: go.etcd.io/etcd upgrade => v3.3.20+incompatiblego: finding module for package github.com/coreos/etcd/etcdmaingo: found github.com/coreos/etcd/etcdmain in github.com/coreos/etcd v3.3.20+incompatiblego: finding module for package sigs.k8s.io/yamlgo: finding module for package google.golang.org/grpc/codesgo: finding module for package github.com/coreos/pkg/capnsloggo: finding module for package google.golang.org/grpc/metadata......go: found github.com/golang/groupcache/lru in github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57ego: go.etcd.io/etcd imports   github.com/coreos/etcd/etcdmain imports github.com/coreos/etcd/etcdserver imports   github.com/coreos/etcd/mvcc/backend imports github.com/coreos/bbolt: github.com/coreos/bbolt@v1.3.4: parsing go.mod:   module declares its path as: go.etcd.io/bbolt   but was required as: github.com/coreos/bbolt

翻车了。看起来coreos维护的bbolt库声明它的module名称是go.etcd.io/bbolt,结果在使用它的时候使用的package path是github.com/coreos/bbolt,不一致啊(etcd#11720, etcd#11739)、etcd#11749。

显然是etcd使用的是错误的bbolt的路径。冷静下来,考虑解决办法。幸好,go module提供replace的方法,我们可以使用下面的方法替换:

1
replace github.com/coreos/bbolt => go.etcd.io/bbolt v1.3.4

现在我们再执行go get -u -v go.etcd.io/etcd,貌似bbolt的问题没有了,但是新问题又来了:

123456789101112131415161718
go: go.etcd.io/etcd upgrade => v3.3.20+incompatiblego: finding module for package github.com/coreos/etcd/etcdmaingo: found github.com/coreos/etcd/etcdmain in github.com/coreos/etcd v3.3.20+incompatiblego: finding module for package github.com/coreos/go-systemd/util......google.golang.org/grpc/resolver/dnsgithub.com/coreos/etcd/clientv3/balancer/resolver/endpointgoogle.golang.org/grpc/balancer/base# github.com/coreos/etcd/clientv3/balancer/resolver/endpoint../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:114:78: undefined: resolver.BuildOption../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:182:31: undefined: resolver.ResolveNowOption......github.com/coreos/etcd/pkg/logutil# github.com/coreos/etcd/clientv3/balancer/picker../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/picker/err.go:37:44: undefined: balancer.PickOptions../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/picker/roundrobin_balanced.go:55:54: undefined: balancer.PickOptionsgithub.com/grpc-ecosystem/grpc-gateway/runtime.....

惊不惊喜,意不意外。跨过了一座山,趟过了一条河,又遇到了一座山。我精神有点恍惚了,作为一个知名的使用量巨大的开源项目,默认go get不应该困难重重啊,即使有bug,这明显的问题应该早就修复了啊。搜一下issue,你会看到etcd#11563、etcd#11650、etcd#11707

Etcd的代码和新版本的grpc(v1.27.0)冲突,再次施展替换大法,让项目使用老的grpc:

123
replace (    google.golang.org/grpc => google.golang.org/grpc v1.26.0)

重新go get -u -v go.etcd.io/etcd,怀着十二分的忐忑,观察下载结果,一顿刷屏之后,终于成功了,泪流满面,面无血色,色即是空,空即是色。

到此告一段落。因为我们没有使用其它的库,要是依赖其它的库,而其它库也在使用某个版本的etcd,或者它没有使用go module,问题不敢想...,不过还好我们的例子还没有使用其它库,目前是依赖了一个etcd。

现在你肯定会有一个疑问,这个问题已经有很多issue,难道etcd没有修改吗?

检查我们的go.mod文件,发现一堆的indirect引用的库,居然还有两个etcd:

123456
......github.com/coreos/etcd v3.3.20+incompatible // indirectgo.etcd.io/etcd v3.3.20+incompatible // indirect......google.golang.org/grpc v1.28.1 // indirect......

命名引入了go.etcd.io/etcd,咋还附赠了一个github.com/coreos/etcd?而且这俩的代码不是都一样的吗?

go.etcd.io/etcd之所以显示为indirect是因为我们的代码中还没有引用这个package。在当前文件夹下创建abc.go文件:

123
package mimport _ "go.etcd.io/etcd"

然后go mod tidy就可以看到go.etcd.io/etcdindirect标记没了。

123456
......github.com/coreos/etcd v3.3.20+incompatible // indirectgo.etcd.io/etcd v3.3.20+incompatible // indirect......google.golang.org/grpc v1.28.1 // indirect......

但是我想默默地问一句,为什么github.com/coreos/etcd还存在?它被标记为indirect,肯定是某个库引用它了。是谁?

go mod why github.com/coreos/etcd是没有用的:

123
➜  abc go mod why github.com/coreos/etcd# github.com/coreos/etcd(main module does not need package github.com/coreos/etcd)

要使用go mod graph找一下,执行这个命名筛选一下:

123
➜  abc go mod graph|grep github.com/coreos/etcdexample.com/m github.com/coreos/etcd@v3.3.20+incompatiblegithub.com/spf13/viper@v1.4.0 github.com/coreos/etcd@v3.3.10+incompatible

原来是github.com/spf13/viper@v1.4.0搞的鬼,github.com/coreos/etcd/etcdmain使用了github.com/spf13/cobra@v0.0.7库, cobra又使用viper的1.4.0版本,而viper@v1.4.0又使用了etcd@v3.3.10。真优秀,绕了一圈又绕回来了,循环依赖啊。但是已经面目全非,原先人家是小甜甜(go.etcd.io/etcd),现在却成了牛夫人(github.com/coreos/etcd)。

暂且不管它们了,好歹至少我们的项目已经没啥冲突了,可以继续开发了。但是我心中还有隐隐有一个声音在呼唤,刨根问底,永不放弃。责任感和历史使命促使我们再问一句: 目前etcd的最高版本是多少了?

其实很好查,到github上查看项目的tags:

可以看到目前etcd项目的最高版本已经到了3.4.7,可我们为什么默认拉下来的版本还是历史久远的v3.3.20+incompatible。为什么?

首先,这个incompatible是啥子意思?依照这个解释,在特定的场景下会加上incompatible标签。

既然etcd都已经到了3.4.7了,我们使用这个最新的版本:

123
➜  abc go get -u -v go.etcd.io/etcd@3.4.7get "go.etcd.io/etcd": found meta tag get.metaImport{Prefix:"go.etcd.io/etcd", VCS:"git", RepoRoot:"https://github.com/etcd-io/etcd"} at //go.etcd.io/etcd?go-get=1go get go.etcd.io/etcd@3.4.7: go.etcd.io/etcd@3.4.7: invalid version: unknown revision 3.4.7

What? 明明官方网站了已经有3.4.7版本了,咋获取不到?

1
GO111MODULE=on go list -m -json -versions go.etcd.io/etcd@latest

显示最新的版本是v3.3.20+incompatible:

1234567
......"v3.3.18+incompatible","v3.3.19+incompatible","v3.3.20+incompatible" ],"Time": "2020-04-01T17:49:03Z"}

如果禁用GOPROXY,最新版本是v2.3.8+incompatible:

123456
"v2.3.6+incompatible","v2.3.7+incompatible","v2.3.8+incompatible"   ],"Time": "2017-02-16T03:25:01Z"}

pkg.go.dev也没有显示最新的版本:

不管怎样,貌似都没有3.4.7版本。实在没招了,etcd的issue中有相关的讨论:etcd#11154,怨声载道,甚至有群众说还好目前大家可以拿新型肺炎病毒搪塞作者不关心这个bug。我看这个bug从去年9月份就开始了,目前没有还没有处理。目前考虑到的处理方法有两个:

  1. 删除etcd库中的go.mod: 直接有效,但是和go官方极力推广go module相背驰

  2. 定义模版为go.etcd.io/etcd/v3。但是这是令人讨厌的事情,go module定义了v0v1v2 module,将module定义整的非常的复杂,也强迫库的开发者非要在go.mod定义版本信息。或许,etcd的作者通过这种方式,来抵制go的这种设计方式。

折腾了一下午,伤痕累累,累觉不爱。

Etcd使用go module的灾难相关推荐

  1. Go Modules 的智障版本选择

    之前 go mod 用的比较少,而且一直听社区有各种抱怨,所以也兴趣寥寥.新公司的项目直接使用了 go mod,本来觉得无非是个简单的工具,不需要学习,结果在一个简单的依赖上却浪费了很多时间. 先来看 ...

  2. cannot find main module 解决办法

    做6.824 实验的过程中想要跑测试,发现go test -run 2A时 出现cannot find main module问题,测试跑不起来. 原因 这个原因是从GO1.11 版本开始引入了go. ...

  3. 服务发现对比:Zookeeper vs. etcd vs. Consul

    欢迎关注方志朋的博客,回复"666"获面试宝典 服务发现工具 手动配置 ZooKeeper ETCD Consul 结论 我们拥有的服务越多,如果我们使用预定义的端口,就会发生冲突 ...

  4. 服务发现:Zookeeper vs etcd vs Consul

    服务发现:Zookeeper vs etcd vs Consul 摘自:http://dockone.io/article/667 [编者的话]本文对比了Zookeeper.etcd和Consul三种 ...

  5. 万级K8s集群背后etcd稳定性及性能优化实践

    作者:唐聪, 腾讯 CSIG 后台开发工程师 本文旨在帮助大家了解 etcd集群场景下稳定性与性能优化经验引的容量,避免给后面留坑. 背景与挑战 随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云 ...

  6. 老是说我编译版本不够_编译etcd出现的cannot load bufio的错误解决办法

    编译etcd出现的cannot load bufio的错误解决办法 今天在安装编译etcd的时候,出现以下错误: go: finding github.com/golang/groupcache v0 ...

  7. etcd (一看就会)

    简介 "etcd"这个名字源于两个想法,即 unix "/etc" 文件夹和分布式系统"d"istibuted. "/etc&qu ...

  8. 分布式键值存储ETCD

    分布式键值存储 前言 实现分布式系统的目标以及挑战 分布式ETCD存储 etcd介绍 基于etcd的使用场景 1.键值对存储 2.服务注册与发现 3.消息发布与订阅 4.分布式锁 etcd相关术语(关 ...

  9. etcd学习和实战:3、go使用etcd实现服务发现和管理

    etcd学习和实战:3.go使用etcd实现服务发现和管理 文章目录 etcd学习和实战:3.go使用etcd实现服务发现和管理 1. 前言 2. 代码及编译运行问题总结 2.1 服务注册 2.2 服 ...

最新文章

  1. s:property 获取 ValueStack中的值
  2. JAVA的String的实现
  3. dependencies与dependencyManagement的区(转自:http://blog.csdn.net/liutengteng130/article/details/46991829)
  4. 如何理解signal函数声明
  5. FTP文件共传输服务
  6. React开发(215):React中的Fragments的动机
  7. LeetCode 2176. 统计数组中相等且可以被整除的数对
  8. redis常规命令记录
  9. Android 刘海屏来袭,全网最全适配技巧
  10. pythonstdin_Python从Stdin读取参数
  11. 打工的人面对老板是没有溢价权的
  12. 应用机器学习(九):主成分分析
  13. php如何以post形式发送xm并返回xmll数据
  14. 使用python爬取链家上海二手房信息的案例
  15. 空降过来的男领导如何管理女性团队?我的一些实操技巧
  16. 用python花猫_Python竟能画这么漂亮的花,帅呆了(代码分享)
  17. matplotlib系列-plt.axis
  18. mysql 增加时间字段
  19. 函数参数传递三种方式(传值方式,地址传递,引用传递)
  20. 【正点原子MP157连载】第十六章 基本定时器实验-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南

热门文章

  1. Shiro安全框架最全面解析
  2. python爬虫爬取商城男装信息
  3. qq飞车手游早上会服务器维护吗,QQ飞车手游4月4日更新后进不去_QQ飞车手游4.4请检查网络后再试试解决方法_游戏吧...
  4. linux驱动PCIE开发
  5. 互联网公司寄件管理教程
  6. 华为鸿蒙系统要多大内存,华为鸿蒙系统实测:内存控制超神,吊打安卓真不是吹牛?...
  7. Linux 批量创建用户脚本
  8. 最优化方法:L1和L2正则化regularization
  9. C#导出Excle表格根据内容动态调整单元格大小
  10. 翌加科技:抖音昵称如何取比较好