0%

Go Micro微服务架构 - 快速上手

本文主要将如何快速启动 M3O 微服务

快速上手

  • 依赖
  • 安装
  • 编写服务

依赖

Protobuf

代码生成依赖 Protobuf , 安装示例:

1
go get github.com/micro/protoc-gen-micro/v2

Discovery

推荐使用 etcd 作为注册中心。

etcd

单机部署参考 Dockerfile, 安装示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM k8s.gcr.io/debian-base:v1.0.0

ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/
RUN mkdir -p /var/etcd/
RUN mkdir -p /var/lib/etcd/

# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
# To fix this we just create /etc/nsswitch.conf and add the following line:
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf

EXPOSE 2379 2380

# Define default command.
CMD ["/usr/local/bin/etcd"]

使用当前目录作为上下文的构建命令:

1
docker build .

安装 go-micro

Go Micro是用于基于Go的开发的框架。

服务中导入 go-micro 示例:

1
import "github.com/micro/go-micro/v2"

建议开启 go mod,并通过 go mod 启用改功能。

1
2
3
4
5
6
# enable go modules
export GO111MODULE=on
# initialise go modules in your app
go mod init
# now go get
go get ./...

编写服务

按照惯例,使用 go-micro 编写一个 helloworld服务,以下是具体步骤。

  • 服务原型
  • 生成原型
  • 编写服务
  • 运行服务
  • 定义客户端
  • 运行客户端

以下操作均在 greeter 目录下进行。

1
# cd /home/eter/greeter

服务原型

创建 proto 目录

1
2
# mkdir proto
# touch proto/greeter.proto

编辑 proto/greeter.proto 文件

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

service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}

message HelloRequest {
string name = 1;
}

message HelloResponse {
string greeting = 2;
}

查看下 greeter 目录,可以看到 proto 目录中只有 greeter.proto 文件。

1
2
3
4
5
greeter
├── go.mod
├── go.sum
└── proto
└── greeter.proto

生成原型

在定义好原型后我们得使用 protoc ,以及 micro 插件编译它,micro 插件可以帮助生成 go micro 需要的原型文件。

1
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. proto/greeter.proto

查看下 greeter 目录,可以看到 proto 目录中生成的文件 greeter.pb.go 以及 greeter.pb.micro.go 。

1
2
3
4
5
6
7
greeter
├── go.mod
├── go.sum
└── proto
├── greeter.pb.go
├── greeter.pb.micro.go
└── greeter.proto

编写服务

  1. 首先编辑greeter的服务代码 main.go 文件

主要功能:

  • 定义并实现Greeter Handler中的接口
  • 初始化 micro.Service
  • 注册 Greeter Handler
  • 运行服务

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
35
package main

import (
"context"
"fmt"

micro "github.com/micro/go-micro/v2"
proto "github.com/eopenio/greeter/proto"
)

type Greeter struct{}

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

func main() {
// 创建新的服务
service := micro.NewService(
micro.Name("greeter"),
micro.Version("v0.0.1"),
)

// 初始化服务,并且解析命令行传参
service.Init()

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

// 启动服务
if err := service.Run(); err != nil {
fmt.Println(err)
}
}

查看下 greeter 目录,可以看到新增 main.go 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
greeter
├── go.mod
├── go.sum
├── main.go
└── proto
├── greeter.pb.go
├── greeter.pb.micro.go
└── greeter.proto
```
### 运行服务
``` bash
# go run main.go
2020-03-22 20:57:40 level=info Starting [service] greeter
2020-03-22 20:57:40 level=info Server [grpc] Listening on [::]:65461
2020-03-22 20:57:40 level=info Registry [etcd] Registering node: greeter-45fc8d75-1db5-48f0-8f5d-71a691e5c982

通过 micro 命令进行查看服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# micro list services
greeter

# micro get service greeter
service greeter

version v0.0.1

ID Address Metadata
greeter-45fc8d75-1db5-48f0-8f5d-71a691e5c982 192.168.3.5:65461 transport=grpc,broker=eats,protocol=grpc,registry=etcd,server=grpc

Endpoint: Greeter.Hello

Request: {
name string
}

Response: {
greeting string
}

定义客户端

新增客户端代码 cli.go 文件。

cli.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
package main

import (
"context"
"fmt"

micro "github.com/micro/go-micro/v2"
proto "github.com/eopenio/greeter/proto"
)


func main() {
// 创建新服务
service := micro.NewService(micro.Name("greeter.client"))
service.Init()

// 创建新的客户端
greeter := proto.NewGreeterService("greeter", service.Client())

// 调用greeter
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "World"})
if err != nil {
fmt.Println(err)
}

// 打印响应请求
fmt.Println(rsp.Greeting)
}
1
2
3
4
5
6
7
8
9
greeter
├── cli.go
├── go.mod
├── go.sum
├── main.go
└── proto
├── greeter.pb.go
├── greeter.pb.micro.go
└── greeter.proto

运行客户端

1
2
# go run cli.go
Hello World

备注

本文示例可以通过以下命令,进行编译.

1
2
3
4
5
6
7
# git clone https://github.com/eopenio/greeter.git

# 启动服务端
# go run main.go

# 启动客户端
# go run cli.go