Grpc 是谷歌开发的一种开源的 RPC 框架。我在学习 Seaweedfs 的时候, 经常会遇到各种各样的 grpc 操作,经过一段时间的学习,在此记录下来。

grpc 中的 'g' 代表的是 Google ,而 rpc 则是一种机制,全称为 Remote Procedure Call,它可以使两个存在物理距离的机器上运行的进程可以 像就在一台机器上一样相互调用,如一个运行在机器 A 中的进程可以调用一个运行在机器 B 上的进程。正是因为这种特性,我们经常会在各 种分布式系统中见到它。

文章 Remote Procedure Call 详细介绍了 rpc 的原理,里面有这么一张图我觉得 非常好,这里贴出来:

图中,客户端利用 rpc 技术调用服务器端的函数。Client Function 首先调用 Client Stub,对于 Client Function 来说 Client Stub 就是它想要 调用的函数,但是 Client Stub 并不是真的函数,因为真的函数是在服务器机器上。但是 Client Function 不知道,它只知道调用 Client Stub 能够得到想要的结果。调用之后,剩下的事情就交给 Client Stub 来完成。Client Stub 把 Client Function 传进来的参数封装成特定格式的数据,通过 Socket 发给 遥远的服务器。服务器这边运行着的 Server Stub,对来自客户端的数据进行解封装,然后传给 Server Function。Server Function 收到之后, 把数据进行运算,并把运算后的结果原路返回。

在了解了 rpc 的原理之后,我们再来看一张图,它和上面那张图出自同一篇文章。

这张图介绍了 rpc 程序的生成过程,我们可以看到图中左边有一个叫做 IDL(Interface Definition Language) 的东西,翻译过来叫做“接口定义语言”, 顾名思义,它就是用来定义进行 rpc 调用的客户端和服务器端的消息格式和内容的一种编程语言。你用 IDL 定义传输消息的格式和内容,经过 RPC Compiler 编译,就生成了图中深蓝色的五样东西,其中就包括上面提到的 Client Stub 和 Server Stub。而程序员要做的就是写一个 Client Function 来调用 Client Stub,加上写一个 Server Function 进行实际的计算操作。

到这里,rpc 的内容基本就讲的差不多了。把上面的内容理解了,学习下面的 grpc 就会轻松许多。

在 grpc 中,IDL 是一种叫做 protocol buffer 的语言。它大致长这个样子:

message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}

对应的 RPC Compiler 叫做 protocol buffer compiler,程序名为protoc

以 grpc 官网给出的 Basic Tutorial 为例,这里有一个用 protocol buffer 写成的文件 route_guide.proto,我们可以用以下命令编译它:

$ protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    routeguide/route_guide.proto

编译成功之后本地会生成两个文件:

  1. route_guide.pb.go:这个文件包含了对 protocol buffer 的一些基本操作,如封装与解封装等,还有信息用编程语言(如golang等)的具体实现。 如我们上面给出的 protocol buffer 的例子message Point,它在 route_guide.pb.go 中就是这个样子的:
type Point struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Latitude  int32 `protobuf:"varint,1,opt,name=latitude,proto3" json:"latitude,omitempty"`
	Longitude int32 `protobuf:"varint,2,opt,name=longitude,proto3" json:"longitude,omitempty"`
}
  1. route_guide_grpc.pb.go:这个文件包含了我们上面提到的 Client Stub 与 Server Stub。

这里要说明的是,Server Stub 也叫 Server Skeleton,“Skeleton”这个单词有“骨架”的意思,也就是说,这里自动生成的只是一个 Server Function 的“空架子”,真正的函数还是要我们程序员来实现的。

下面简单介绍一下 Grpc 信息交流的四种方式:

  1. 简单模式(Simple RPC)

这种 RPC 就是简单的1 : 1模式,客户端函数传一个值给服务器端,服务器函数再回复一个值给客户端,如 Basic Tutorial 中的 GetFeature函数

  1. 服务器端流模式(Server-side streaming RPC)

这种模式是客户端发一个数据给服务器端,服务器端回复一串数据流给客户端,如 Basic Tutorial 中的 ListFeatures函数

  1. 客户端流模式(Client-side streaming RPC)

这种模式是客户端发一串数据给服务器端,服务器端回复一个数据流给客户端,如 Basic Tutorial 中的 RecordRoute函数

  1. 双向数据流模式(Bidirectional streaming RPC)

这种模式是客户端一串一串数据流的发,服务器端一串一串的回,如 Basic Tutorial 中的 RouteChat函数

以上。