go微服务调用报错too many colons in address
问题描述:
我提取了关键部分的代码编写了单元测试,方便测试问题。给大家参考一下。这原先是大佬给的案例,我没见过这种写法,出于兴趣就按照案例写了一个demo,结果一写就出现报错。
func TestSrvConn(t *testing.T) {
consulInfo := global.ServerConfig.Consul
address := fmt.Sprintf("consul://%s:%d/%s?wait=14s", consulInfo.Host, consulInfo.Port, global.ServerConfig.GrpcSrv.Name)
var bulider = NewBuilder()
userConn, err := grpc.Dial(
address,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy": "round_robin"}`),
grpc.WithResolvers(bulider),
)
if err != nil {
fmt.Println("111", err)
}
userSrvClient := proto.NewFileStoreGreeterClient(userConn)
ping := proto.Ping{Stroke: 1111}
res, err := userSrvClient.PingPong(context.Background(), &ping)
fmt.Println("res", res)
fmt.Println("err:::", err)
fmt.Println("end")
}
然后,直接调用srv服务没问题,调用通过consul发现的srv服务会有此报错;
transport: Error while dialing dial tcp: address consul://192.168.32.90:8500/fileStore-srv?wait=14s: too many colons in address
问题分析
简单来说就是解析器的问题。如果你不是和我一样基于 conusl 协议的,可以尝试把地址写成[协议://ip地址]:端口/endpoint 或者 [账号@密码:地址]:端口/endpoint 这样说不定就解决了(也就是:端口 前面的内容用中括号括起来)。
而grpc的包中,没有consul 协议的解析器。所以会报错。
但是我对大佬给的模板debug时惊奇地发现,居然能看到consul.Resolver这个解析器,也就是说,它被自动引入了。
我在模板代码里找了半天,又去grpc的包中找,再去consul的包中去查找,都找不到哪里有些这个解析器。
快要放弃了的时候,突然灵光一闪,自动引入…
解决方案
其实在发现问题原因前,已经找到替代方案了。这样钻牛角尖,纯粹为了技术研究,拖这个问题的福,我对gprc底层的通信的实现原理大致全新的理解。
最终方案1:
import _ "github.com/mbobakov/grpc-consul-resolver"
就这么简单,懂的都懂…
替代方案: 通过client.Agent().ServicesWithFilter 这个方法来发现服务并调用
improt ""github.com/hashicorp/consul/api""
client, err := api.NewClient(cfg)
if err != nil {
panic(err)
}
data, err := client.Agent().ServicesWithFilter(fmt.Sprintf(`Service=="%v"`, srvName))
if err != nil {
panic(err)
}
for _, value := range data {
global.ServerConfig.GrpcSrv.Host = value.Address
global.ServerConfig.GrpcSrv.Port = value.Port
break
}
两种方案的区别
grpc-consul-resolver 这个包导入即用,不需要关心任何实现过程。是基于grpc通信解析开发的解析器。每次进行函数请求时,都会通过consul来转发到服务端,而不是直接和服务端通信。
client.Agent().ServicesWithFilter 这个方法是consul包内置的。可以用来自定义负载均衡的策略。简单易于理解,新手也有能力自行开发新功能。但是这个方法是基于http请求的,如果每次请求时,都调用这个方法,会损失一定性能。
|