Skip to content

本文将演示如何从 0 到 1 使用 go-micro 框架实现 RPC 微服务,包括服务端和客户端,客户端发送一个名字到服务端,服务端返回问候语。

一、创建项目

创建项目目录,使用 go mod 初始化

go
mkdir goexamples
go mod init goexamples

如果当前项目在 GOPATH 目录之外,记得设置

go env -w GO111MODULE=on

目录结构如下:

proto/greeter.proto: 接口定义代码

client.go: 客户端代码

server.go: 服务端代码

一、编写 Proto 文件

go-micro 框架 使用 gRPC 进行 远程过程调用,而 gRPC 使用 Google 开发的数据交换格式和接口定义语言:Protobuf (Protocol Buffers)在不同服务之间进行数据通信、序列化和反序列化。

所以需要编写 Protobuf 文件来定义 Request、Response、Interface,文件扩展名 为 .proto ,用于定义数据结构和消息格式。

编写 greeter.pb 文件,内容如下:

go
// Proto文件使用的协议版本,新项目建议采用proto3
syntax = "proto3"; 

// 分号前面是包路径(根据包路径自动创建目录),后面是包名
option go_package = "../proto;proto";

// 定义接口
service Greeter {
	rpc Hello(HelloRequest) returns (HelloResponse) {}
}

// 定义输入参数
message HelloRequest {
	string name = 1;
}

// 定义输出参数
message HelloResponse {
	string msg = 1;
}

这段代码是一个简单的示例,用于定义一个名为 "Say" 的微服务,该服务包含一个 "Hello" RPC 方法,用于问候。 "Request" 和 "Response" 消息定义了方法的输入和输出。

这个Proto文件可以用来生成不同编程语言的代码,以便在客户端和服务端之间实现消息的序列化和反序列化以及RPC通信。

二、生成 Proto Go 代码

要根据 Proto 文件生成 Go 代码,你需要使用 Protobuf 编译器 protoc 以及 Go 的 Protobuf 插件。以下是生成 Go 代码的步骤:

安装 Protobuf 编译器  protoc

前往 Protocol Buffers 的 GitHub Release 页面 https://github.com/protocolbuffers/protobuf/releases,选择适合你操作系统的最新 protoc 版本并下载安装,mac 可以直接用 brew install protobuf 安装

安装完成后,你可以在终端中运行以下命令来验证 protoc 是否成功安装,如果 protoc 成功安装,它将显示安装的版本号

protoc --version

安装 protoc-go

Go 的 Protobuf 插件允许你从 Proto 文件生成 .go 代码,默认会安装到$GOPATH/go/bin目录下

bash
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

安装 protoc-gen-micro

go-micro 框架 protoc-gen-micro 插件 允许你从 Proto 文件生成 .micro.go 代码,默认会安装到$GOPATH/go/bin目录下

go
go install github.com/go-micro/generator/cmd/protoc-gen-micro@latest

生成 Go 代码

使用 protoc 编译器来生成 Go 代码,假设你有一个名为 greeter.proto 的 Proto 文件,并且你希望生成 Go 代码。cd 到 proto目录,在终端中执行以下命令:

bash
protoc --go_out=. --micro_out=. greeter.proto

--go_out 指定了生成  .go 代码的目标目录,这里使用当前目录(".") --micro_out 指定了生成 .micro.go 代码的目标目录,这里使用当前目录(".") greeter.proto 是你的 Proto 文件名

运行上述命令后,你将在当前目录下看到生成的 Go 代码文件,包括消息结构和序列化/反序列化方法。生成的文件名称将与你的 .proto 文件名称相对应,但会使用 ".pb.go" 作为扩展名。

如果你的 .proto 文件名为 greeter.proto,则生成的 Go 代码文件将是 greeter.pb.go

如果遇到下面这个错误,则需要将 $GOPATH/bin 加入到 path 环境变量

protoc-gen-micro: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
vim ~/.bash_profile
export PATH=$PATH:/Users/mc/go/bin // 替换这里的GOPATH目录,比如我的是/Users/mc/go
source ~/.bash_profile

三、编写服务端代码

编写server.go,用于实现服务端:

go
package main

import (
	"context"
	"log"

	pb "goexamples/proto" // proto 接口定义

	"go-micro.dev/v4" // 引入 go-micro 框架
)

// 定义 Greeting 服务
type GreetingService struct{}

// 实现 proto 接口定义 的 Greeting 服务
func (s *GreetingService) Hello(ctx context.Context, req *pb.HelloRequest, rsp *pb.HelloResponse) error {
	rsp.Msg = "Hello, " + req.Name
	return nil
}

func main() {
	// 创建微服务实例
	service := micro.NewService(
		micro.Name("greeter"),
	)
	// 接收命令行参数  如--server_address
	service.Init()

	// 注册 Greeting 服务
	pb.RegisterGreeterHandler(service.Server(), new(GreetingService))

	// 运行微服务
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}
}

四、编写客户端代码

编写client.go,用于实现客户端:

go
package main

import (
	"context"
	"fmt"

	pb "goexamples/proto"

	"go-micro.dev/v4"
)

func main() {
	// 创建微服务实例
	service := micro.NewService()

	// 接收命令行参数  如--server_address
	service.Init()

	// 创建 Greeting 客户端存根
	cl := pb.NewGreeterService("greeter", service.Client())

	// 发送请求
	rsp, err := cl.Hello(context.Background(), &pb.HelloRequest{
		Name: "muchuang",
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.Msg)
}

五、编译和运行

现在,你可以使用以下命令编译和运行服务端和客户端:

bash
# 下载代码库依赖
go get go-micro.dev/v4
go mod tidy

# 编译服务端
go build -o server server.go

# 编译客户端
go build -o client client.go

# 运行服务端
./server

# 在另一个终端中运行客户端
./client

客户端将发送一个名字到服务端,服务端将返回一个问候语,客户端会打印出这个问候语。这是一个简单的Go-Micro微服务示例,演示了微服务之间的通信。请确保根据你的项目需要和Proto文件定义进行适当的修改。

六、参考

micro 代码生成器:https://github.com/go-micro/generator

go-micro 框架:https://github.com/go-micro/examples/tree/main/greeter

木川工作室 (微信:mcmc2024)