共计 4310 个字符,预计需要花费 11 分钟才能阅读完成。
得益于 Go 语言的编译快性能高特点,在云原生时代其作为服务端编程语言发展迅速,尤其是微服务领域,已逐渐形成一个良好的生态,基于 Golang 的微服务框架如今有很多,如 go-kit、go-micro、kite、gizmo 等,每一种都自有其优点。今天就来探一探 go-micro 框架。
一、go-micro 是什么
go-micro 是基于 Go 语言实现的插件化 RPC 微服务框架,与 go-kit,kite 等微服务框架相比,它具有易上手、部署简单、工具插件化等优点。
go-micro 框架提供了服务发现、负载均衡、同步传输、异步通信以及事件驱动等机制,它尝试去简化分布式系统间的通信,让我们可以专注于自身业务逻辑的开发。所以对于新手而言,go-micro 是个不错的微服务实践的开始。
二、go-micro 架构
2.1 分层架构
下图为官方博客提供的 go-micro 架构图:
go-micro 是组件化的框架,每一个基础功能都是一个 interface,方便扩展。同时,组件又是分层的,上层基于下层功能向上提供服务,整体构成 go-micro 框架。go-micro 的组件包括:
Registry 组件:服务发现组件,提供服务发现机制:解析服务名字至服务地址。目前支持的注册中心有 consul、etcd、zookeeper、dns、gossip 等
Selector 组件:构建在 Registry 之上的客户端智能负载均衡组件,用于 Client 组件对 Registry 返回的服务进行智能选择。
Broker 组件:发布 / 订阅组件,服务之间基于消息中间件的异步通信方式,默认使用 http 方式,线上通常使用消息中间件,如 Kafka、RabbitMQ 等。
Transport 组件:服务之间同步通信方式。
Codec 组件:服务之间消息的编码 / 解码。
Server 组件:服务主体,该组件基于上面的 Registry/Selector/Transport/Broker 组件,对外提供一个统一的服务请求入口。
Client 组件:提供访问微服务的客户端。类似 Server 组件,它也是通过 Registry/Selector/Transport/Broker 组件实现查找服务、负载均衡、同步通信、异步消息等功能。
所有以上组件功能共同构成一个 go-micro 微服务。
2.2 微服务之间通信
两个微服务之间的通信是基于 C / S 模型,即服务发请求方充当 Client,服务接收方充当 Server。其通信过程大致如下图:
上图大致描绘了 go-micro 服务内各组件的职责与交互。
三、实现一个简单的微服务
纸上得来终觉浅,下面就来搭建环境,实现一个简单的基于 go-micro 的微服务。为简单起见,client 与 server 之间我们使用点对点的同步方式(Transport),即无需消息中间件(Broker),注册中心采用 consul 系统。
3.1 安装 consul – 注册中心
服务注册中心我们选择 consul:
mac:brew install consul
windows:直接官网下载 consul.exe 可执行程序
运行 consul:启动 Consul agent 的开发模式:
consul agent -dev
该命令快速启动一个单节点的 consul,且为集群的领袖
查看 Consul 集群的成员:打开另一个终端执行:
consul members
停止 Agent:使用 Ctrl-C,优雅的关闭 Agent
也可以通过 WebUI 来查看各 service 状态:http://localhost:8500/
3.2 安装 micro:微服务管理工具
micro 是以 go-micro 框架为核心的微服务管理工具,通过它可以方便查看 go-micro 服务情况。
在 $GOPATH 目录下,执行 go get github.com/micro/micro,该命令会在 bin 目录($GOBIN)下生成 micro(.exe) 工具 micro 命令行工具可以提供诸如服务列表查看、服务详情查看、调用服务接口等功能。
3.3 安装 goprotobuf 相关工具:GRPC 相关工具
protoc:Protobuf(Protocol Buffers – Google’s data interchange format)编译器:
windows 下直接下载 相关 win 的 zip 压缩文件(内含 protoc.exe)
mac:brew install protobuf
protoc-gen-go:goprotobuf 提供的 Protobuf 插件:在 $GOPATH 目录下执行 go get github.com/micro/protobuf/{proto,protoc-gen-go},该命令会在 bin 目录下生成 protoc-gen-go(.exe) 工具,protoc 编译器利用 protoc-gen-go 插件将.proto 文件转换为 Golang 源文件
protoc-gen-micro(Protobuf code generation for micro):在 $GOPATH 目录下执行 go get github.com/micro/protoc-gen-micro,该命令会在 bin 目录下生成 protoc-gen-micro(.exe),protoc 编译器利用 protoc-gen-micro 插件将.proto 文件转换为 micro 代码风格文件
goprotobuf 编译参数:
- I 参数:指定 import 路径,可以指定多个 - I 参数,编译时按照顺序查找,不指定时默认查找当前目录
–go_out:Golang 编译支持,支持以下参数
– `plugins=plugin1+plugin2`:指定插件,支持 grpc/micro,即:plugins=grpc+micro
– `M` 参数:指定导入的.proto 文件路径编译后对应的 goalng 包名(不指定默认.proto 文件中 import 语句路径)
– `import_prefix=xxx`:为所有 import 路径添加前缀,主要用于编译子目录内的多个 proto 文件
– `import_path=foo/bar`:指定未声明 package 或 go_package 的文件的包名,最右边的斜线前的字符会被忽略
3.4 编写一个简单的 Hello 服务
至此,go-micro 框架的编程环境已基本搭建好,接下来就是写代码了。
下面实现一个 Hello 服务:它接收一个字符串类型参数请求,返回一个字符串问候语:Hello『参数值』。1)定义 API
创建 proto/hello.proto 文件:使用 protobuf 文件来定义服务 API 接口
syntax = “proto3”;
service Hello {
rpc Ping(Request) returns (Response) {}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
执行 protoc 命令,生成当前 pb 文件的 go 实现:
protoc –go_out=plugins=micro:. ./proto/hello.proto
2)创建 service
创建 services/hello.go 文件:
package main
import (
“context”
“fmt”
proto “winmicro/proto”
micro “github.com/micro/go-micro”
)
type Hello struct{}
func (h *Hello) Ping(ctx context.Context, req *proto.Request, res *proto.Response) error {
res.Msg = “Hello ” + req.Name
return nil
}
func main() {
service := micro.NewService(
micro.Name(“hellooo”), // 服务名称
)
service.Init()
proto.RegisterHelloHandler(service.Server(), new(Hello))
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
3) 模拟 client
创建 Clients/helloclient.go 文件:
package main
import (
“context”
“fmt”
proto “winmicro/proto”
micro “github.com/micro/go-micro”
)
func main() {
service := micro.NewService(micro.Name(“hello.client”)) // 客户端服务名称
service.Init()
helloservice := proto.NewHelloService(“hellooo”, service.Client())
res, err := helloservice.Ping(context.TODO(), &proto.Request{Name: “World ^_^”})
if err != nil {
fmt.Println(err)
}
fmt.Println(res.Msg)
}
3.5 运行 Hello 服务
启动 consul 之后执行 micro list services 查看当前已有服务:
> micro list services
consul
执行 go run services/hello.go 命令,启动 hellooo 服务:
>go run services/hello.go
2018/11/29 20:18:08 Listening on [::]:61463
2018/11/29 20:18:08 Broker Listening on [::]:61464
2018/11/29 20:18:08 Registering node: hellooo-74122f56-4728-4449-a9d4-6c3c85ba2fcb
….
再次执行 micro list services 查看当前已有服务:
> micro list services
consul
hellooo
即 hellooo 服务已启动
注 通过 WebUI 来查看各 service 信息:http://localhost:8500/
请求服务执行 go run clients/helloclient.go 命令,向 hellooo 服务发起请求:
>go run clients/helloclient.go
Hello World ^_^
References
https://github.com/micro/go-m…https://micro.mu/docs/go-micr…https://lixiangyun.gitbooks.i…https://github.com/hb-go/micro