學習微服務框架是為了更了解各種架構對不同專案上的適應性
雖然並不是每個專案都適合為服務,但是也需要先熟練各種兵器好應對更種情況
介紹
go-micro 是一個使用 go 實現的微服務框架,可以方便幫助 go 進行微服務的開發
主要功能
- 服務發現
- 平衡負載
- Client/Server
- Pub/Sub
- gRPC
Require
Install
安裝工具
1
2
3
4
|
go mod init .
go get github.com/micro/micro/v2@v2.4.0
go get -u github.com/golang/protobuf/protoc-gen-go@v1.3.0
go get -u github.com/micro/protoc-gen-micro/v2@v2.3.0
|
mod version
這邊遇到了一些麻煩的狀況,各個版本的相依性很高,不同版本搭配可能造成錯誤
所以在這邊提供的以下的版本是確定可運行的
1
2
3
4
5
6
7
8
|
go 1.14
require (
github.com/golang/protobuf v1.4.2
github.com/micro/go-micro/v2 v2.9.1
github.com/micro/protoc-gen-micro/v2 v2.3.0 // indirect
google.golang.org/grpc v1.26.0
)
|
Simple
我試著使用各種寫法來實現簡單的範例
使用 go-micro 進行服務發現,再透過 grpc 進行傳輸
Proto
一個簡單的 Request/Respone
syntax = "proto3";
option go_package= ".;rpc";
service Greeter {
rpc Hello (Request) returns (Response){};
}
message Request {
string name = 1;
}
message Response {
string greeting = 2;
}
然後透過以下語法進行轉換,會得到除了 grpc 的 go file 以外,還會得到給 go-micro 使用的 go file
1
2
3
4
|
protoc proto/*.proto --go_out=plugins=grpc:rpc --micro_out=rpc
# hello.pb.go
# hello.pb.micro.go
|
Server
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
36
37
38
39
|
package main
import (
"context"
"fmt"
pb "github.com/cody0704/grpc_example01/rpc"
micro "github.com/micro/go-micro/v2"
"github.com/micro/go-micro/v2/server/grpc"
)
type Greeter struct {
}
func (g *Greeter) Hello(context context.Context, req *pb.Request, rsp *pb.Response) error {
rsp.Greeting = "Hello " + req.Name
return nil
}
func main() {
service := micro.NewService(
micro.Name("cody.micro.srv.hello"),
micro.Version("latest"),
)
sServer := service.Server()
sServer.Init(
grpc.MaxMsgSize(2 * 1024 * 1024 * 1024),
)
err := pb.RegisterGreeterHandler(sServer, new(Greeter))
if err != nil {
fmt.Println(err)
}
if err := service.Run(); err != nil {
fmt.Println(err)
}
}
|
Client
會在範例中使用那麼多參數
主要是因為沒有找到有人教學如何使用相關參數的使用
官方的文檔貌似不是那麼齊全
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
36
37
38
39
40
41
42
43
|
package main
import (
"context"
"log"
"time"
pb "github.com/cody0704/micro_example01/rpc"
micro "github.com/micro/go-micro/v2"
clientOpt "github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/grpc"
)
func main() {
// Create a new service
service := micro.NewService(
micro.Name("hello.client"),
)
service.Init()
client := service.Client()
client.Init(
clientOpt.Retries(3),
clientOpt.DialTimeout(60*time.Second),
clientOpt.RequestTimeout(60*time.Second),
clientOpt.Retry(func(ctx context.Context, req clientOpt.Request, retryCount int, err error) (bool, error) {
log.Println(req.Method(), retryCount, " client retry")
return true, nil
}),
grpc.MaxRecvMsgSize(2*1024*1024*1024),
grpc.MaxRecvMsgSize(2*1024*1024*1204),
)
helloClient := pb.NewGreeterService("cody.micro.srv.hello", client)
rsp, err := helloClient.Hello(context.TODO(), &pb.Request{Name: "Cody"})
if err != nil {
log.Println(err)
}
log.Println(rsp.GetGreeting())
}
|
Run
然後進行運行
1
2
3
4
5
6
7
8
9
|
# terminal 1
go run server/main.go
> 2020-09-18 11:16:20 file=v2@v2.9.1/service.go:200 level=info Starting [service] cody.micro.srv.hello
> 2020-09-18 11:16:20 file=grpc/grpc.go:864 level=info Server [grpc] Listening on [::]:52355
> 2020-09-18 11:16:20 file=grpc/grpc.go:697 level=info Registry [mdns] Registering node: cody.micro.srv.hello-d7e523ea-c574-400b-8bac-b664d4f30b9c
# terminal 2
go run client/main.go
2020-09-18 11:16:32.070476 I | Hello Cody
|
結論
由於只有一對一,所以運行起來感覺會跟一般的 gRPC 相同,不過底層是透過 multicast 進行呼叫進行呼叫
所以不用指定 IP 位址,取而代之的是一個定義的名稱進行呼叫
Ref
- 使用 go-micro 的时候 etcd,grpc-gateway 产生冲突
- Go Micro 中文文档 - 发布订阅
- Micro In Action