没有输出的输入是不完整的

0%

【微服务Go-micro第一篇】环境配置

go-micro 是一个基于Go语言的分布式框架,可以用来对外提供微服务。
本篇文章介绍如何在linux系统下进行环境配置,并写好自己的第一个helloworld程序。

本文是 2020 年 Go Micro v2 的学习记录,使用 protoc 3.11.4 和 protoc-gen-go v1.21.0。当时没有保存 Go、Micro 及 examples 的完整版本组合,复现时需要先确认兼容版本,并保存 go.mod 和 go.sum。下面的 go get 是当年的工具安装方式;Go 1.18 起,安装工具请按 官方说明 使用 go install ...@明确版本。

一、依赖安装

  1. 依赖安装 protoc-gen-micro

先将 MICRO_V2_VERSION 设置为已确认兼容的 Micro v2 tag/commit,再将 go env GOPATH 对应目录下的 bin(或自定义 GOBIN)加入 PATH,让 protoc 能找到两个插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 依赖
go get github.com/micro/micro/v2/cmd/protoc-gen-micro@${MICRO_V2_VERSION:?请先设置已确认兼容的Micro_v2版本}

# 上述包依赖两个protoc 和protoc-gen-go

# 第一个依赖安装
# [protobuf下载](https://github.com/protocolbuffers/protobuf/releases)
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip

unzip protoc-3.11.4-linux-x86_64.zip -d /root/go/gotool/

# 路径修改
vim ~/.bash_profile
PATH=/root/go/gotool/bin:$PATH
source ~/.bash_profile

# 检查是否安装成功,如果出现版本号,则说明安装成功。
protoc --version


# 第二个依赖protoc-gen-go的安装
go get google.golang.org/protobuf/cmd/protoc-gen-go@v1.21.0
  1. 依赖安装 etcd
1
2
3
4
5
6
7
8
wget https://github.com/etcd-io/etcd/releases/download/v3.4.7/etcd-v3.4.7-linux-amd64.tar.gz

tar -xzf etcd-v3.4.7-linux-amd64.tar.gz

sudo cp etcd-v3.4.7-linux-amd64/etcd etcd-v3.4.7-linux-amd64/etcdctl /usr/local/bin/

# 通过如下命令来启动
etcd

要声明etcd来进行注册服务,在bash_profile中添加如下内容

1
export MICRO_REGISTRY=etcd

如果碰到用go get 命令报403错误可以使用代理来解决。

1
2
3
4
5
vim ~/.bash_profile
# 添加如下内容

export GOPROXY=https://goproxy.io # 设置代理
source ~/.bash_profile
  1. 通过go-module来管理依赖
    在bash_profile中添加如下内容
1
export GO111MODULE=on

二、helloworld程序

2.1 官方实例的helloworld

先将 MICRO_EXAMPLES_REF 设为与工具链兼容的 examples 提交。服务端会一直在前台运行,所以最后两个 go run 命令要在两个终端分别执行。

1
2
3
4
5
6
7
8
go get github.com/micro/micro/v2@${MICRO_V2_VERSION:?请先设置已确认兼容的Micro_v2版本}

git clone https://github.com/micro/examples.git
cd examples
git checkout "${MICRO_EXAMPLES_REF:?请先设置与Micro_v2匹配的examples提交}"
cd service
go run main.go
go run main.go --run_client

结果会出现

1
hello john

说明实验成功。

2.2 自己编写helloworld测试

  1. 构造项目

自己的项目还需要 Go Micro v2 运行库,将 GO_MICRO_V2_VERSION 设为兼容的 tag/commit 即可。它和前面的 Micro 工具属于不同模块,版本号要分别确认。

1
2
3
4
5
6
# 建立项目
mkdir hello && cd hello

# 利用模块来管理相关的依赖。
go mod init hello
go get github.com/micro/go-micro/v2@${GO_MICRO_V2_VERSION:?请先设置已确认兼容的Go_Micro_v2版本}
  1. 编写服务原型
1
2
3
# 在hello目录下建立服务原型
mkdir proto
vim proto/greeter.proto

greeter.proto 内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
syntax = "proto3";

service Greeter {
rpc Hello(Request) returns (Response) {}
}

message Request {
string name = 1;
}

message Response {
string greeting = 2;
}
  1. 根据服务原型生成对应的代码
1
2
# 在hello目录下执行
protoc --proto_path=. --micro_out=. --go_out=. proto/greeter.proto

本文环境下,hello/proto目录中会有下面三个文件。部分插件版本将微服务文件命名为 greeter.micro.go;使用较新生成器时,还需按 Go 生成代码指南 设置 go_package 和输出路径。

1
2
3
greeter.pb.go  
greeter.pb.micro.go
greeter.proto
  1. 编写main.go文件作为服务器代码。
1
vim main.go

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"context"
"fmt"

micro "github.com/micro/go-micro/v2"
proto "hello/proto"
)

type Greeter struct{}

func (g *Greeter) Hello(ctx context.Context, req *proto.Request, rsp *proto.Response) error {
rsp.Greeting = "Hello " + req.Name
return nil
}

func main() {
// Create a new service. Optionally include some options here.
service := micro.NewService(
micro.Name("greeter"),
)

// Init will parse the command line flags.
service.Init()

// Register handler
proto.RegisterGreeterHandler(service.Server(), new(Greeter))

// Run the server
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
  1. 编写client.go文件作为客户端代码。
1
vim client.go

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"context"
"fmt"

micro "github.com/micro/go-micro/v2"
proto "hello/proto"
)

func main() {
// Create a new service
service := micro.NewService(micro.Name("greeter.client"))
// Initialise the client and parse command line flags
service.Init()

// Create new greeter client
greeter := proto.NewGreeterService("greeter", service.Client())

// Call the greeter
rsp, err := greeter.Hello(context.TODO(), &proto.Request{Name: "kingwen"})
if err != nil {
fmt.Println(err)
return
}

// Print response
fmt.Println(rsp.Greeting)
}
  1. 运行程序

分别在三个终端运行下面的命令,并确保客户端、服务端读取到相同的 MICRO_REGISTRY=etcd 设置。

1
2
3
4
5
6
# 终端一(若 etcd 已启动则不用重复启动)
etcd
# 终端二,在 hello 目录
go run main.go
# 终端三,也在 hello 目录
go run client.go

结果出现

1
Hello kingwen

说明程序搭建成功。

最后看一下代码结构

1
2
3
4
5
6
7
8
9
10
├── client.go
├── default.etcd
│ └── member
├── go.mod
├── go.sum
├── main.go
└── proto
├── greeter.pb.go
├── greeter.pb.micro.go
└── greeter.proto

三、参考链接

  1. 基于 Go Module 管理依赖并将注册中心调整为 Etcd
  2. go-micro-github地址
  3. Go Micro v2 API 文档