做网站南宁,建立的近义词,福州网站建设公司哪家好,南京网站建设索q.479185700go: v1.20.3
go-zero: v1.5.4
etcd: v3.5.9 问题描述
在 go-zero 中用 etcd 去实现服务注册发现#xff0c;rpc 服务可以注册到 etcd#xff0c;同时其他服务可以发现注册的微服务#xff0c;也可以访问。但是#xff0c;注册的 rpc 服务的日志#xff0c;就是一直报以…go: v1.20.3
go-zero: v1.5.4
etcd: v3.5.9 问题描述
在 go-zero 中用 etcd 去实现服务注册发现rpc 服务可以注册到 etcd同时其他服务可以发现注册的微服务也可以访问。但是注册的 rpc 服务的日志就是一直报以下错误。日志一直在刷 Auto sync endpoints failed 的问题服务也可以访问就很诡异。
{level:warn,ts:2023-07-30T15:57:02.0040800,logger:etcd-client,caller:v3v3.5.4/retry_interceptor.go:62,msg:retrying of unary invoker failed,target:etcd-endpoints://0xc0007281c0/192.168.2.2:2379,attempt:0,error:rpc error: code DeadlineExceeded desc latest balancer error: last connection error: connection error: desc \transport: Error while dialing dial tcp 0.0.0.0:2379: connect: connection refused\}
{level:info,ts:2023-07-30T15:57:02.0040800,logger:etcd-client,caller:v3v3.5.4/client.go:210,msg:Auto sync endpoints failed.,error:context deadline exceeded}如果是老手看到这里 应该知道问题会出在哪里。我是菜鸟就只好一步步分析。 如果想直接看解决方法的到最后下面是我的分析过程。 排查
当出现问题的时候想的就是包的问题不是我的问题。就去 trace go-zero 的源码也就是 etcd 注册的那个地方。
把 go-zero封装 etcd 的源码看了好几遍也没发现有问题都是正常的注册与发现。(注意这时候我 go-zero 版本还是 v1.3.2)
没什么问题以为是 go-zero 版本太旧了升级一下。因为看 issue 说 etcd 版本也有可能太旧。
验证一
把 go-zero 版本升级到 v1.5.4(中间是先到v1.4.4)把 etcd 升级到 v3.5.9(中间是先到v3.5.7)发现并没有成功还是会出现 Auto sync endpoints failed。 想想 go-zero 应该也不至于会出这个问题会不会是我 etcd 启动的问题我是用 docker 启动的 etcd因为是在测试就用单点。这边对配置的 IP 其实没有概念也不知道都是干嘛的。
docker run -d --name ai-etcd --networkhost --restart always \-v $PWD/etcd.conf.yml:/opt/bitnami/etcd/conf/etcd.conf.yml \-e ETCD_ADVERTISE_CLIENT_URLShttp://0.0.0.0:2379 \-e ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379 \-e ETCD_LISTEN_PEER_URLShttp://0.0.0.0:2380 \-e ETCD_INITIAL_ADVERTISE_PEER_URLShttp://0.0.0.0:2380 \-e ALLOW_NONE_AUTHENTICATIONyes \bitnami/etcd:3.5.9这个 docker 的启动方式也是往上找的没问题呀。启动也 okgo-zero 也注册得上去。
再看看 etcd 到底哪里出的问题又去看了下源码。
// client.go L196
func (c *Client) autoSync() {if c.cfg.AutoSyncInterval time.Duration(0) {return}for {select {case -c.ctx.Done():returncase -time.After(c.cfg.AutoSyncInterval):ctx, cancel : context.WithTimeout(c.ctx, 5*time.Second)err : c.Sync(ctx)cancel()if err ! nil err ! c.ctx.Err() {c.lg.Info(Auto sync endpoints failed., zap.Error(err))}}}
}// Sync synchronizes clients endpoints with the known endpoints from the etcd membership.
func (c *Client) Sync(ctx context.Context) error {mresp, err : c.MemberList(ctx)if err ! nil {return err}var eps []stringfor _, m : range mresp.Members {...}c.SetEndpoints(eps...)return nil
}上面这个方法报错因为 Auto sync endpoints failed 是一直出现的说明 go-zero 里面有个地方应该也配置了 AutoSyncInterval 所以这边会跑这个。下面是go-zero 调用的地方其实也就是初始化一个etcd client的传参。
// registry.go L337
// DialClient dials an etcd cluster with given endpoints.
func DialClient(endpoints []string) (EtcdClient, error) {cfg : clientv3.Config{Endpoints: endpoints,AutoSyncInterval: autoSyncInterval,DialTimeout: DialTimeout,DialKeepAliveTime: dialKeepAliveTime,DialKeepAliveTimeout: DialTimeout,RejectOldCluster: true,PermitWithoutStream: true,}...
}此时此刻很无奈感觉不知道往哪里思考。服务也没报错也能调用就又很不想去分析。这种问题就很折磨关键日志很多很丑。还是多找找吧去看 go-zero 的 issue看到也有人提这个问题不过都没有什么解决方案。去看 etcd 的 issue也没有看到什么。最后也不知道怎么地想为什么要一直带着 go-zero 去想这个问题我自己写一个 etcd client 试一下不就行了。找了个范例测一下不就知道是 go-zero 的问题还是 etcd 起的有问题。
范例我就不详细列了可以去看我的另一篇 【etcd】docker 启动单点 etcd_非晓为骁的博客-CSDN博客 的文章。
cli, err clientv3.New(clientv3.Config{Endpoints: []string{192.168.2.2:2379},DialTimeout: time.Second * 5,AutoSyncInterval: time.Second * 5,
})同样也设置了 AutoSyncInterval结果难受香菇竟然也会报这个错误。 这里有一个很重要的点不要出了问题就局限在你用的框架里面更要会抽丝剥茧简单地看问题。 这时候说明 etcd 部的就是有问题的只好再看下 docker run 的指令和错误。我把错误减少到下面这一行仔细看下可以看到是服务 dial 0.0.0.0:2379 失败。rpc 服务和 etcd 是在 2 台服务器访问本地 2379 就是访问容器内 2379那肯定访问不到呀。关键是 0.0.0.0:2379 拿来的呢
rpc error: code DeadlineExceeded desc latest balancer error: last connection error: connection error: desc \transport: Error while dialing dial tcp 0.0.0.0:2379: connect: connection refused\rpc 的配置配的是 etcd 的 host肯定不是 0.0.0.0:2379。那说明是 etcd 服务自身返回回来的。这时候只好去分析 docker run 里面的 url。4 个有 2 个是 2380说明不是我要关注的剩下 2 个应该就是问题本身。另外 2 个 2380看起来是 cluster 相关的所以也可以直接忽略。
-e ETCD_ADVERTISE_CLIENT_URLShttp://0.0.0.0:2379 \-e ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379 \
看了下注释
ETCD_LISTEN_CLIENT_URLS List of comma separated URLs to listen on for client traffic.ETCD_ADVERTISE_CLIENT_URLSList of this member’s peer URLs to advertise to the rest of the cluster. The URLs needed to be a comma-separated list.
我理解的是 ETCD_LISTEN_CLIENT_URLS 是监听的 IP:PORT谁可以访问这个服务类似我们其他服务用的 bind所以这个用 0.0.0.0 应该没问题。ETCD_ADVERTISE_CLIENT_URLS 这看起来是要通知别人要访问这个 IP:PORT 才可以访问到我看起来好像是这个的问题。改成我的服务器 IP 试试。
验证二
docker run -d --name ai-etcd --networkhost --restart always \-v $PWD/etcd.conf.yml:/opt/bitnami/etcd/conf/etcd.conf.yml \-e ETCD_ADVERTISE_CLIENT_URLShttp://192.168.2.2:2379 \-e ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379 \-e ALLOW_NONE_AUTHENTICATIONyes \bitnami/etcd:3.5.9emmm这样子在用我 etcd 的范例测试一下果真没有报错了。为自己的愚蠢感到深深的无语还一直以为是 go-zero 的问题其实跟 go-zero 一点关系都没有。 总结
这个问题出现了很久从 v1.3.2 开始就有。但一直分析不出来就搁置而且不影响使用。最后还是洁癖看不惯分析这个问题。一开始就先入为主地看是 go-zero 的问题去看 issue去百度google但都带上了 go-zero。其实就不是它的问题自己的分析能力还是不够。etcd 这边 docker 启动的方式大部分都是一样的启动起来好像也没啥问题也不会往那边去想。
这个问题深层次原因应该还是对 etcd 不了解里面的一些 url 不了解。而且需要多去尝试用最小单元去做测试这样才可以事半功倍。
解决方案
etcd docker run 的 ETCD_ADVERTISE_CLIENT_URLS 要改成服务器 IP然后 rpc 服务重新注册。 这个是我自己分析的过程及理解可能这里面还有更深层次的问题有懂的大佬可以分享一下。