基于 Go Micro 框架构建一个简单的微服务接口
友情提示:由于 Go Micro 已经将 Consul 从开箱支持调整为插件支持,所以本篇教程对于新手已经不再适用,最新版本教程在这里:https://laravel.geekai.co/post/21585。
今天,学院君将通过一个简单的 HelloWorld 示例给大家演示下如果基于 Go-Micro 框架进行微服务开发。学院君的本地开发环境和工具是 Mac + GoLand,如果你本地还没有安装 Go 语言开发环境,请参考这篇教程安装设置。
0、创建新项目
打开 GoLand,创建一个新项目 hello
:
创建成功后,进入该项目,设置项目 GOPATH
路径:
1、安装 Protobuf
打开 GoLand 自带的 Terminal,运行如下命令安装 protoc-gen-micro,该工具可以帮助我们快速生成微服务模板代码:
该工具依赖 protoc 和 protoc-gen-go,所以要使用 protoc-gen-micro
还要安装它们。
可以从这里 https://github.com/protocolbuffers/protobuf/releases 下载最新版的 protoc:
选择与自己系统相匹配的压缩包,比如我的是 Mac 系统,则选择 osx 64 位下载,解压,然后将其移动到指定位置(可选),并将 protoc
二进制可执行文件所在的 bin
目录放到系统路径中:
mv ~/Downloads/protoc-3.8.0-osx-x86_64 ~/go/tools
vi ~/.zshrc
export PATH="/Users/sunqiang/go/tools/protoc-3.8.0-osx-x86_64/bin:$PATH"
source ~/.zshrc
运行 protoc --version
检测是否可以在任意位置调用 protoc
命令:
然后在 hello
项目根目录下安装 protoc-gen-go
(还是在 GoLand 的 Terminal 中执行):
go get -u github.com/golang/protobuf/protoc-gen-go
安装完成后,可以看到 protoc-gen-go
可执行文件会被安装到项目根目录下的 bin
目录下:
表明安装成功。
2、服务发现
接下来,我们设置基于 Consul 进行服务发现,为此,需要在系统中安装 Consul,可以从 Consul 下载页面 选择与自己系统匹配的下载包下载(比如这里学院君选择的是 macOS 64-bit):
下载完成后,解压到本地,是一个二进制可执行文件,将其移动到指定位置(可选):
mv ~/Downloads/consul ~/go/tools/
然后和 protoc
一样,将 consul
添加到系统路径中,并设置一个新的系统环境变量 MICRO_REGISTRY
以便被 Go Micro 使用:
vi ~/.zshrc
export PATH="/Users/sunqiang/go/tools:$PATH"
export MICRO_REGISTRY=consul
source ~/.zshrc
接下来,运行 consul
命令验证是否安装成功:
3、编写服务
至此,微服务所依赖的基本工具都已经安装设置好了,下面我们来编写一个微服务接口。
创建服务接口原型
在 ~/go/hello/src
目录下新建一个 hello
子目录,并在该 hello
子目录下创建一个 proto
目录,然后在 proto
目录下创建一个服务接口原型文件 greeter.proto
,我们通过 protobuf 定义服务接口如下:
syntax = "proto3";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 2;
}
如上述代码所示,我们定义了一个名为 Greeter
的服务,该服务中包含一个 Hello
方法,该方法接收一个 HelloRequest 对象,然后返回一个 HelloResponse 对象,这两个对象都只包含一个参数。
通过接口原型生成代码
接下来,我们就可以借助第 1 步安装的 protoc
工具通过接口原型生成相应的服务代码(在 GoLand的 Terminal 窗口中执行):
cd ~/go/hello/src/hello
protoc --proto_path=. --micro_out=. --go_out=. proto/greeter.proto
执行成功的话,会在 proto
目录下生成两个新的 Go 文件:
其中 greeter.pb.go
由 protoc-gen-go
生成,包含了 HelloRequest
和 HelloResponse
类代码;greeter.micro.go
由 protoc-gen-micro
生成,包含了 Greeter
服务相关的实现代码。
编写服务端代码
接下来,我们在 ~/go/hello/src/hello
创建一个 main.go
用作服务端入口:
package main
import (
"context"
"fmt"
proto "hello/proto"
micro "github.com/micro/go-micro"
)
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = " 你好, " + req.Name
return nil
}
func main() {
// 创建新的服务
service := micro.NewService(
micro.Name("Greeter"),
)
// 初始化,会解析命令行参数
service.Init()
// 注册处理器,调用 Greeter 服务接口处理请求
proto.RegisterGreeterHandler(service.Server(), new(Greeter))
// 启动服务
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
启动服务端
由于我们在代码中引入了远程的包,所以在启动服务端之前,需要先安装这个依赖:
go get github.com/micro/go-micro
然后启动 Consul 代理,以便服务端启动时可以将服务注册到 Consul 中,从而被客户端调用:
这样,我们就可以运行 main.go
来启动服务端了:
go run main.go
在命令行中,可以看到使用的通信协议以及服务注册到注册中心的信息:
此时,在浏览器中访问 http://localhost:8500
,也可以看到 Greeter
服务已经注册成功了:
接下来,就可以通过客户端调用这个远程服务了,我们来编写一段简单的客户端测试代码。
4、编写客户端
在 ~/go/hello/src/hello
目录下创建一个 client.go
用于客户端测试:
package main
import (
"context"
"fmt"
"github.com/micro/go-micro"
proto "hello/proto"
)
func main() {
// 创建一个新的服务
service := micro.NewService(micro.Name("Greeter.Client"))
// 初始化
service.Init()
// 创建 Greeter 客户端
greeter := proto.NewGreeterService("Greeter", service.Client())
// 远程调用 Greeter 服务的 Hello 方法
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "学院君"})
if err != nil {
fmt.Println(err)
}
// Print response
fmt.Println(rsp.Greeting)
}
运行这段 Go 代码,就可以在命令行打印如下信息,表示客户端调用远程服务成功:
至此,我们就基于 Go Micro 框架创建了第一个微服务接口,关于里面涉及到的底层实现原理,我们后面会详细介绍,下一篇,学院君将演示如何从 PHP 项目中(即以 PHP 项目作为客户端)调用基于 Go 实现的微服务接口。
65 Comments
看起来有空指针异常 排查下自己的代码 1、服务是否注册成功 2、调用代码是否有问题
我用go mod包管理 即使在go path目录下面也不行 一直出现上面的情况
go mod 不能在 go path 目录下使用 后面我再写一篇基于 go mod + etcd 的教程吧 现在 consul 迁出到 plugins 里面了
你到 consul web 界面里面看看服务是否注册成功
go run main.go --registry=mdns 这样启动
帅哥可以分享一下吗? go run main.go --registry=consul 这样会失败 但是 go run main.go --registry=mdns 是可以的 consul agent -dev http://localhost:8500/ui/dc1/services 是正常的 求指点 谢谢
NAME: - a go-micro service
USAGE: main [global options] command [command options] [arguments...]
COMMANDS: help, h Shows a list of commands or help for one command
GLOBAL OPTIONS: --client value Client for go-micro; rpc [$MICRO_CLIENT] --client_request_timeout value Sets the client request timeout. e.g 500ms, 5s, 1m. Default: 5s [$MICRO_CLIENT_REQUEST_TIMEOUT] --client_retries value Sets the client retries. Default: 1 (default: 1) [$MICRO_CLIENT_RETRIES] --client_pool_size value Sets the client connection pool size. Default: 1 (default: 0) [$MICRO_CLIENT_POOL_SIZE] --client_pool_ttl value Sets the client connection pool ttl. e.g 500ms, 5s, 1m. Default: 1m [$MICRO_CLIENT_POOL_TTL] --register_ttl value Register TTL in seconds (default: 60) [$MICRO_REGISTER_TTL] --register_interval value Register interval in seconds (default: 30) [$MICRO_REGISTER_INTERVAL] --server value Server for go-micro; rpc [$MICRO_SERVER] --server_name value Name of the server. go.micro.srv.example [$MICRO_SERVER_NAME] --server_version value Version of the server. 1.1.0 [$MICRO_SERVER_VERSION] --server_id value Id of the server. Auto-generated if not specified [$MICRO_SERVER_ID] --server_address value Bind address for the server. 127.0.0.1:8080 [$MICRO_SERVER_ADDRESS] --server_advertise value Used instead of the server_address when registering with discovery. 127.0.0.1:8080 [$MICRO_SERVER_ADVERTISE] --server_metadata value A list of key-value pairs defining metadata. version=1.0.0 [$MICRO_SERVER_METADATA] --broker value Broker for pub/sub. http, nats, rabbitmq [$MICRO_BROKER] --broker_address value Comma-separated list of broker addresses [$MICRO_BROKER_ADDRESS] --profile value Debug profiler for cpu and memory stats [$MICRO_DEBUG_PROFILE] --registry value Registry for discovery. etcd, mdns [$MICRO_REGISTRY] --registry_address value Comma-separated list of registry addresses [$MICRO_REGISTRY_ADDRESS] --runtime value Runtime for building and running services e.g local, kubernetes (default: "local") [$MICRO_RUNTIME] --selector value Selector used to pick nodes for querying [$MICRO_SELECTOR] --transport value Transport mechanism used; http [$MICRO_TRANSPORT] --transport_address value Comma-separated list of transport addresses [$MICRO_TRANSPORT_ADDRESS] --help, -h show help
consul agent -dev 通过http://localhost:8500/ui/dc1/services 正常的 但是 go run main.go --registry=consul 这样会失败 但是 go run main.go --registry=mdns 是可以的 希望学院君能抽空看一下 谢谢
解决吗?
mdns和etcd都看可以 consul始终弄不成功 唉
consul被移到另一个库了,main.go要改一下: Ps:我用了go modules管理,导入的地方要注意一下,大致就是micro要重新注册一个consul服务
最后成功运行结果 $ go run client.go 你好, 学院君