go微服务调用报错too many colons in address

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 {
		//zap.S().Fatal("[InitSrvConn] 连接 【用户服务失败】")
		fmt.Println("111", err)
	}
	
	//下面这段时尝试调用PingPong方法,测试是否在正常输出
	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)
}

//根据服务名或id查询grpc服务端地址
data, err := client.Agent().ServicesWithFilter(fmt.Sprintf(`Service=="%v"`, srvName))
if err != nil {
	panic(err)
}

for _, value := range data {
	//把连接的gprc服务地址和端口复制到全局变量
	global.ServerConfig.GrpcSrv.Host = value.Address
	global.ServerConfig.GrpcSrv.Port = value.Port
	break
}

两种方案的区别

grpc-consul-resolver 这个包导入即用,不需要关心任何实现过程。是基于grpc接口实现的专门针对consul的通信协议解析器。这个解析器的特点是每次进行函数请求时,都会通过consul来转发到服务端,而不是直接和服务端通信

client.Agent().ServicesWithFilter 这个方法是consul包内置的。可以用来自定义负载均衡的策略。简单易于理解,新手也有能力自行开发新功能。但是这个方法是基于http请求的,如果每次请求时,都调用这个方法,会损失一定性能。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值