gRPC初涉

好久之前就听说过微服务这个东西,但一直只是停留在表面,最近相对有时间就抽空了解了下微服务。
维基百科对微服务的定义:

微服务 (Microservices) 是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模组化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic) 的 API 集相互通讯。

而RPC(远程过程调用)框架为微服务提供了基本的消息传递模式。今天就来简单地了解下Google的gRPC框架

什么是gPRC: gRPC 是由谷歌开发的一款高性能、开源和通用的 RPC 框架。

接下来就开始了解它吧~

正如其他 RPC 系统,gRPC 基于如下思想:定义一个服务, 指定其可以被远程调用的方法及其参数和返回类型。gRPC 默认使用 protocol buffers 作为接口定义语言,来描述服务接口和有效载荷消息结构。如果有需要的话,可以使用其他替代方案。

看到gRPC默认使用 protocol buffers 作为接口定义语言,那么有必要了解下什么是 protocol buffers

protocol buffers :

是一种序列化数据结构的协议。对于透过管线(pipeline)或存储数据进行通信的程序开发上是很有用的。这个方法包含一个接口描述语言,描述一些数据结构,并提供程序工具根据这些描述产生代码,用于将这些数据结构产生或解析数据流。

简单地说,就是Google 公司内部的混合语言数据标准,按这个标准编写接口定义就好啦。

查看文档,了解到,gRPC有以下4种服务方式:

  1. 单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。
  2. 服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。
  3. 客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。
  4. 双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。

本次就简单地用 单项 RPC 来实现调用,为了加深自己对Golang的理解,本次使用Golang语言的gRPC。

先根据文档搭建好Go相关的gRPC环境 :

$ go get google.golang.org/grpc # 安装 gRPC 框架
$ go get -u github.com/golang/protobuf/protoc-gen-go # 安装 Go 版本的 protobuf 编译器

一切准备好后,先照着官方demo撸下。

这边简单地解释下官方demo下的 route_guide(以单项 RPC为例)。

route_guide 是个根据定位来获取相应地名的一个demo,它主要有以下请求流程:

1.Client 端通过 NewRouteGuideClient 来调用预定义的 GetFeature
2.Server 端 GetFeature 接收请求参数,返回Point对应地名,如果没有就返回空

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
func main() {
flag.Parse()
var opts []grpc.DialOption
if *tls {
if *caFile == "" {
*caFile = testdata.Path("ca.pem")
}
creds, err := credentials.NewClientTLSFromFile(*caFile, *serverHostOverride)
if err != nil {
log.Fatalf("Failed to create TLS credentials %v", err)
}
opts = append(opts, grpc.WithTransportCredentials(creds))
} else {
opts = append(opts, grpc.WithInsecure())
}
conn, err := grpc.Dial(*serverAddr, opts...)
if err != nil {
log.Fatalf("fail to dial: %v", err)
}
defer conn.Close()
client := pb.NewRouteGuideClient(conn)

// Looking for a valid feature
printFeature(client, &pb.Point{Latitude: 409146138, Longitude: -746188906})

// Feature missing.
printFeature(client, &pb.Point{Latitude: 0, Longitude: 0})
}

//Todo