原创

go-micro In Action

什么是 go-micro

go-micro是一个后台微服务开发框架,它提供了一个分布式系统开发所需的核心要求;其最大的特点是它是一个可插拔的架构,它对分布式系统的各个组成部分都抽象成接口,例如:

  • 客户端/服务端(Client/Server)
  • 服务发现(Registry)
  • 异步消息通信(Broker)
  • 负载均衡(Selector)
  • 传输层(Transport)
  • ...
go-micro 官方架构图

什么是可插拔?就是你可以直接使用go-micro的默认实现或者在go-plugins中选择基于不同组件实现的插件库;甚至你可以基于go-micro框架抽象的接口来实现自己的插件库。

以上就是关于go-micro框架的简单说明,下面的内容会记录个人在具体项目中使用go-micro框架的心得以及问题总结(持续更新),希望能为大家提供一些帮助:

gprc.NewService() vs micro.NewService()

go-micro中主要提供了两种创建micro.Service的方式:

  1. gprc.NewService()
  2. micro.NewService()

第一种方式下底层传输协议使用的是grpc;第二种方式下底层传输协议使用的是http + protobuf。从实际比较来看,gprc的性能明显好于micro。关于两者的差异可参考这篇stackoverflow提问

micro.Service 全局化

在一个微服务中,一般会以Server的身份来提供服务,但是很多时候还会以Client的身份来调用其他微服务。我们通过示例代码来详细看一下:

以下Server的示例代码(一般为main.go中),会创建一个micro.Service实例:

service := gprc.NewService()
service.Init()
// ...
proto.RegisterXXXServiceHandler(service.Server(), handler)
// ....
sevice.Run()

以下Client的示例代码,每次都创建一个micro.Service实例:

service := gprc.NewService()
service.Init()
// ...
client := proto.NewXXXService("XXX", service.Client())
// ...

综上,其实我们可以在main.go中创建一个全局的Service来进行复用,而不是每次来新创建一个。

micro.Service初始化

使用命令行参数或者环境变量

micro web 工具

go-micro为我们提供了一个叫micro web的工具,它会以页面的形式为我们提供以下三个功能:

  1. CLI:一个命令行工具,你可以通过输入help来使用;
  2. Registry:列出了所有微服务,并可查看某个微服务的详情,例如Nodes,Endpoints等信息;
  3. Call: 直接在页面上调试某个微服务的接口。

以上这些方便我们调试某个微服务,以及查看微服务的健康情况等;不过有一点要注意的是,Call功能默认使用micro.NewService方式来调用的,如果你的微服务使用的是grpc.NewService的话,需要在执行命令micro web时增加相关参数。

问题总结

一. "go.micro.client", "request timeout", 408 问题原因总结

原因一:全局环境变量设置了http代理

go-micro中你可以使用micro.NewService或者grpc.NewService来创建micro.Service,这两种方式的区别是底层传输协议的不一样,前者是http,后者用的是grpc,但是不管怎么样,最终都是基于http的。所以如果你设置了http代理,就会出现408 Request Timeout的问题。以micro.NewService为例,我们来追溯一下源代码:

// 代码调用流程:Client.Call -----> Transport.Dial
// 涉及代码文件:rpc_client.go, transport.go http_transport.go http_proxy.go
// 源代码位于 micro/transport/http_proxy.go
func getURL(addr string) (*url.URL, error) {
	r := &http.Request{
		URL: &url.URL{
			Scheme: "https",
			Host:   addr,
		},
	}
	return http.ProxyFromEnvironment(r)
}

上面注释中的ClientTransport都是go-micro抽象出来的接口,请注意最后一行http.ProxyFromEnvironment(r),它的作用是:如果你设置了http代理,那么它就会把代理地址返回,这样就导致Transport.Dial接口调用超时,go-micro框架会返回408错误。

// 源代码位于 net/http/transport.go
func ProxyFromEnvironment(req *Request) (*url.URL, error) {
	return envProxyFunc()(req.URL)
}

那么golangnet/http包是如何获取代理地址的呢?请看下面的代码(golang version >= 1.11),就是根据几个环境变量来的:

// 源代码位于 x/net/http/httpproxy/proxy.go
func FromEnvironment() *Config {
	return &Config{
		HTTPProxy:  getEnvAny("HTTP_PROXY", "http_proxy"),
		HTTPSProxy: getEnvAny("HTTPS_PROXY", "https_proxy"),
		NoProxy:    getEnvAny("NO_PROXY", "no_proxy"),
		CGI:        os.Getenv("REQUEST_METHOD") != "",
	}
}

在golang 1.10中没有使用上述几个环境变量,通过查阅1.10版本的proxy.go源代码文件可以确认。

原因二: context.Context 使用不规范

func Hello(ctx context.Context, req *Request, rsp *Response) {
  go func() {
      // use ctx for other rpc call
  }()
}

出现408问题的情况除了第一种之外,还有一个情况。如上述示例代码所示,Hello是一个rpc接口:在其内部实现中起了一个goroutine,而这个goroutine内部又使用外部的ctx去调用了另外rpc接口。这种情况下,只有在grpc.NewService这种方式下来创建micro.Service才会出现该问题。所以这个估计与grpc-gogo-micro grpc的实现有关系,有兴趣的话,可以追一下它们的代码实现。

另外,再推荐三篇关于Context的文章,其中摘录了一段,可能是上述情况的原因:

当顶层的Request请求处理结束,或者外部取消了这次请求,就可以cancel掉顶层context,从而使整个请求的routine树得以退出。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • go微服务框架go-micro深度学习(二) 入门例子

        上一篇帖子简单介绍了go-micro的整体框架结构,这一篇主要写go-micro使用方式的例子,中间会穿插一些go-micro的源码,和调用流程图,帮大...

    lpxxn
  • 推荐6-Go maps in action 翻译

    hash table 可能是计算机科学领域最重要的一种数据结构,不同的实现方式会有不同的特性,但通常来说都会提供快速查找、增加和删除的操作。Go 内置了一个名为...

    猿哥
  • go微服务框架go-micro深度学习(四) rpc方法调用过程详解

    上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注...

    lpxxn
  • 《go in action》第4章读书笔记

    如果使用…替代数组的长度,Go语言会根据初始化时数组元素的数量来确定该数组的长度。

    跑马溜溜的球
  • Go语言micro之快速搭建微服务

    go-micro给我们提供了一个非常便捷的方式来快速搭建微服务,而且并不需要提前系统了解micro,下面用一个简单的示例来快速实现一个服务。

    平也
  • 《Go in action》读后记录:Go的并发与并行

    Tencent JCoder
  • 《GO IN ACTION》读后记录:GO的并发与并行

    一、使用goroutine来运行程序 1. Go的并发与并行 Go的并发能力,是指让某个函数独立于其他函数运行的能力。当为一个函数创建goroutine时,该函...

    李海彬
  • DSL In Action

    关于 Anko-Layouts框架的好处和局限性,网上已经有大部分文章在讲,它好在用DSL的方式来描述View,而缺点在于无法即时预览,在这方面导致Anko D...

    bennyhuo
  • micro微服务 基础组件的组织方式

    micro是go语言实现的一个微服务框架,该框架自身实现了为服务常见的几大要素,网关,代理,注册中心,消息传递,也支持可插拔扩展。本本通过micro中的一个核心...

    魂祭心
  • Comparison of Apache Stream Processing Frameworks: Part 2

    In the previous post we went through the necessary theory and also introduced po...

    首席架构师智库
  • go-micro 本地搭建及使用consul

    码缘
  • Golang 语言怎么使用 go-micro 和 gin 开发微服务?

    Go Micro 是一个分布式系统开发框架。Go Micro 提供了分布式系统开发的核心需求,包括 RPC 和事件驱动的通信。Gin 是一个用 Golang 编...

    frank.
  • Comparison of Apache Stream Processing Frameworks: Part 1

    A couple of months ago we were discussing the reasons behind increasing demand f...

    首席架构师智库
  • 微服务系列笔记之Mico Api详解

    上一篇文章中有了入门案例,现在是不是有了很好的理解,不过有个前提是你需要了解grpc技术,简单的来说grpc是一个通信框架,micro是类似的一个通信框架,只不...

    陌无崖
  • Netty in action ——— Bootstrapping

    tomas家的小拨浪鼓
  • Netty in Action ——— ByteBuf

    tomas家的小拨浪鼓
  • Custom Lint in Action

    Android Lint是Google提供的静态代码检查工具,使用Lint可以对Android项目源码进行扫描和检查,发现代码潜在的问题,或者辅助开发者统一编码...

    宅男潇涧
  • ​GoLANG IN ACTION 2020

    因为头脑发热选择go语言?我想可能不是,在经过一系列的了解和调研后,我是认真的选择了golang, 当Rob Pike不满C++委员会要新添加35中新特性之后,...

    公众号: 云原生生态圈
  • Github项目推荐 | 最优控制、强化学习和运动规划等主题参考文献集锦

    References on Optimal Control, Reinforcement Learning and Motion Planning

    AI研习社

扫码关注云+社区

领取腾讯云代金券