目录
gRPC服务端使用C++构建,客户端可以使用Ruby或者Java构建,客户端通过一个Stub存根(代理)对象发起RPC调用,请求和响应消息都使用Protocol Buffer进行序列化。
当我们在微服务中使用gRPC时,整个服务调用过程如下所示(图片来自网络)

通过gRPC,远程服务的调用对使用者更加简单和透明,底层的传输方式,序列化方式,通信细节等统统不需要关系,当然这些对其他RPC框架而言也适用。
2. 使用Protocol Buffers进行服务定义
一个直观的想法,在客户端调用服务端提供的远程接口前,双方必须进行一些约定,比如接口的方法签名,请求和响应的数据结构等,这个过程称为服务定义。服务定义需要特定的接口定义语言(IDL)来完成,gRPC中默认使用protocol buffers。它是google很早就开源的一款序列化框架,其定义了一种数据序列化协议,独立于语言和平台,提供了多种语言的实现:Java,C++,Go等,每一种实现都包含了相应语言的编译器和库文件。使用它进行服务定义需要编写.proto后缀的IDL文件,并通过其编译器生成特定语言的数据结构、服务端接口和客户端Stub代码。
2.1 定义消息
消息是表示RPC接口的请求参数和响应结果的数据结构。如下定义了一个请求消息和响应消息
//定义请求消息的结构 message SearchResponse { // repeated表示该字段可以重复任意次,等价于数组:Result[] repeated Result result = 1; } //定义响应消息的结构 message Result { //required表示该字段的值恰好为1个 required string url = 1; //optional表示该字段的值为0或1个 optional string title = 2; repeated string snippets = 3; }定义消息的关键字为message,相当于java中的class关键字,一个消息就相当于java中的一个类。消息内可以有多个字段,字段的类型可以分类如下
-
基本数据类型
int32表示java中的int,int64表示java中的long,string表示java中的string,具体的对应关系如下表所示

- 复杂数据类型
枚举,map等。
enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; }map<key_type, value_type> map_field = N;和java中类中可以定义类一样,Protocol Buffers中消息内也可以定义消息,形成多层的嵌套结构
message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 required int64 ival = 1; optional bool booly = 2; } }关于消息定义,有几点需要注意的地方
1.消息中的字段前可以有修饰符,修饰符主要有三种-
required
required int64 ival = 1;
该字段的值恰好只有一个,没有或传入多个都将报错。 -
optional
optional int32 result_per_page = 3 [default = 10];
该字段的值有0个或1个,传入多个将报错。且以optional修饰的字段可以设置默认值,若没有设置,则编译器会根据类型自动设置一个默认值,比如string设置为空字符串,bool类型设置为false等。 -
repeated
repeated int32 samples = 4
该字段相当于java中的数组,可以有0个或多个值。
2.消息中的字段有唯一编号,如下所示

这个唯一编号用来在消息的二进制格式中进行字段的区分,范围从1-229 - 1,其中19000-19999是保留编号不能使用。这些字段编号在使用过程中不能进行修改,否则会出现问题。
2.2 定义服务接口
标题中的接口可以类比java中的Interface,内部可以有多个方法。gRPC中使用service关键定义服务接口
service HelloService { &n-
