关于gRPC和golang实现微服务的记录(一)

关于gRPC和golang实现微服务的记录(一)

四月 10, 2019

RPC(Remote Procedure Call)是远程过程调用,比如说现在有两台服务器A, B,一个在A服务器上的应用想要调用B服务器上的应用提供的某个,由于不在两个方法不在一个内存空间,不能直接调用,需要通过网络表达调用的语义和传达调用的数据。常存在于分布式系统中。


探讨tcp/http和RPC的区别的话,这里就不重复探讨了,戳:https://www.jianshu.com/p/959030de7f1c

gRPC是什么

gRPC是谷歌开源的一个 RPC 框架,面向移动和 HTTP/2 设计。

服务端负责实现定义好的接口并处理客户端的请求,客户端根据接口描述直接调用需要的服务。客户端和服务端可以分别使用gPRC支持的不同语言实现。

ProtoBuf 具有强大的IDL(interface description language,接口描述语言)和相关工具集(主要是protoc)。用户写好.proto描述文件后,protoc可以将其编译成众多语言的接口代码。

有了 gRPC, 我们可以一次性的在一个 .proto 文件中定义服务并使用任何支持它的语言去实现客户端和服务器,反过来,它们可以在各种环境中,从Google的服务器到你自己的平板电脑—— gRPC 帮你解决了不同语言及环境间通信的复杂性.使用 protocol buffers 还能获得其他好处,包括高效的序列号,简单的 IDL 以及容易进行接口更新。

Protobuf是什么

Protobuf是一种平台无关、语言无关、可扩展且轻便高效的序列化数据结构的协议,可以用于网络通信和数据存储。

使用和使用前

https://github.com/protocolbuffers/protobuf/releases

将protoc下载下来,设置环境变量,后面将只会展示编译生成的golang代码,protobuf支持其他多种语言

golang 工具

拉取 golang的 grpc包

1
2
# 在大陆的话,可以从https://github.com/grpc/grpc-go,将代码克隆下来放到你的gopath目录下src创建对应的文件夹存入
go get google.golang.org/grpc

代码实现

学习推荐: https://blog.csdn.net/lihao19910921/article/details/80166399

初始代码结构

  • demo
    • hello
      • client
        • main.go
      • server
        • main.go
    • proto
      • hello.proto

编写proto协议文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// demo/proto/hello.proto
// 指定protobuf的版本
syntax = "proto3"

// 指定包名
package hello;

// 定义服务
service HelloService {
// 定义rpc方法 request response
rpc SayHello(HelloRequest) returns (HelloResponse) {}
}

// 请求结构
message HelloRequest {
string name = 1;
}

// 响应结构
message HelloResponse {
string message = 1;
}

使用protoc将.proto文件编译成golang代码,包含服务端接口HelloServer描述,客户端接口及实现HelloClient,及HelloRequest、HelloResponse结构体

1
2
3
# demo/proto/hello.proto
# 使用grpc框架
protoc -I . --go_out=plugins=grpc:. ./hello.proto

新的目录结构如下:

  • demo
    • hello
      • client
        • main.go
      • server
        • main.go
    • proto
      • hello.proto
      • hello.pb.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
36
37
38
39
40
41
42
43
44
45
46
47
// demo/hello/server/main.go

package main

import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
pb "microservice-demo/gRPC/demo/proto"
"net"
)

const (
// gRPC服务地址
addr = "127.0.0.1:3000"
)

// helloService 实现约定的接口
type helloService struct {
}

var HelloService = helloService{}

func (h helloService) SayHello(_ context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
res := new(pb.HelloResponse)
res.Message = "Hello " + req.Name + "."

return res, nil
}

func main() {
listen, err := net.Listen("tcp", addr)
if err != nil {
grpclog.Fatalf("failed to listen: %v", err)
}

// 实例化gRPC server
s := grpc.NewServer()

// 注册hello服务
pb.RegisterHelloServer(s, HelloService)

fmt.Println("Listen on " + addr)

s.Serve(listen)
}

客户端

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

import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
pb "microservice-demo/gRPC/demo/proto"
)

const (
// gRPC服务端服务地址
addr = "127.0.0.1:3000"
)

func main() {
// 连接
conn, err := grpc.Dial(addr, grpc.WithInsecure())

if err != nil {
grpclog.Fatalln(err)
}

defer conn.Close()

// 初始化客服端
c := pb.NewHelloClient(conn)

// 调用服务方法
reqBody := new(pb.HelloRequest)
reqBody.Name = "tomonori"
// 返回的是HelloResponse 响应结构体
r, err := c.SayHello(context.Background(), reqBody)
if err != nil {
grpclog.Fatalln(err)
}

// 输出响应信息
fmt.Println(r.Message)
}

最终结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 在服务端实现的接口方法
...

func (h helloService) SayHello(_ context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
res := new(pb.HelloResponse)
res.Message = "Hello " + req.Name + "."

return res, nil
}
...

...
reqBody := new(pb.HelloRequest)
reqBody.Name = "tomonori"
// 返回的是HelloResponse 响应结构体
r, err := c.SayHello(context.Background(), reqBody)
if err != nil {
grpclog.Fatalln(err)
}

// 输出响应信息
fmt.Println(r.Message)
// Hello tomonori
...

阅读资料

https://blog.csdn.net/lihao19910921/article/details/80166399
http://doc.oschina.net/grpc?t=60133