命令记不住

登陆

gRPC 和 protobuf 简介

gRPC和protobuf简介

1.gRPC简介

  • 高性能
  • 跨平台
  • 流行度,前景

grpc是Google开源的rpc实现,基于最新的HTTP2.0协议,并支持常见的众多编程语言。

与许多RPC系统类似,gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得开发者能够更容易地创建分布式应用和服务。

gRPC理念:
  • 定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。
  • 在服务端实现这个接口,并运行一个gRPC服务器来处理客户端调用。

gRPC客户端和服务端可以在多种环境中运行和交互,并且可以用任何 gRPC 支持的语言来编写。所以,开发者可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、 Python、Ruby来创建客户端。

gRPC默认使用protoBuf,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON )。

2.gRPC的4种模式

gRPC主要有4种请求/响应模式:

  • 简单模式(Simple RPC)

    • 客户端发起一次请求,服务端响应一个数据,即标准RPC通信。
  • 服务端数据流模式(Server-side streaming RPC)

    • 这种模式是客户端发起一次请求,服务端返回一段连续的数据流。典型的例子是客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端。
  • 客户端数据流模式(Client-side streaming RPC)

    • 与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。典型的例子是物联网终端向服务器报送数据。
  • 双向数据流模式(Bidirectional streaming RPC)

    • 这是客户端和服务端都可以向对方发送数据流,这个时候双方的数据可以同时互相发送,也就是可以实现实时交互。比如聊天应用。

长连接的思考:

效率提升

维持连接的代价

重连机制

3.protobuf简介

protobuf特点
  • 序列化后体积相比Json和XML很小,适合网络传输
  • 支持跨平台多语言
  • 消息格式升级和兼容性还不错
  • 序列化反序列化速度很快,快于Json的处理速速
protobuf代码示例:
syntax = "proto3";                  

message HelloRequest {
  string name = 1; 
  int32 height = 2;       
  string email = 3;          
  repeated int32 weight = 4 [packed=true];      
}

message TestResponse {
    string text = 1;
}
protobuf语法
1.修饰前缀
  • optional:表示该字段可以是0或1个,后面可加default默认值,如果不加,使用默认值
  • repeated:表示该字段可以是0到多个,packed=true 代表使用高效编码格式
注意:
  • id在1-15之间编码只需要占一个字节,包括Filed数据类型和Filed对应数字id
  • id在16-2047之间编码需要占两个字节,所以最常用的数据对应id要尽量小一些
  • 使用required规则的时候要谨慎,因为以后结构若发生更改,这个Filed若被删除的话将可能导致兼容性的问题。
2.默认值
  • strings:默认是一个空string
  • bytes:默认是一个空的bytes
  • bools:默认是false
  • 数值类型:默认是0
3.保留字段与id

每个字段对应唯一的数字id,但是如果该结构在之后的版本中某个Filed删除了,为了保持向前兼容性,需要将一些id或名称设置为保留的,即不能被用来定义新的Field。

message Person {
  reserved 2, 15, 9 to 11;
  reserved "samples", "email";
}
4.枚举类型

比如电话号码,只有移动电话、家庭电话、工作电话三种,因此枚举作为选项,如果没设置的话枚举类型的默认值为第一项。在上面的例子中在个人message中加入电话号码这个Filed。如果枚举类型中有不同的名字对应相同的数字id,需要加入option allow_alias = true这一项,否则会报错。枚举类型中也有reserverd Filed和number,定义和message中一样。

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phones = 4;
}
5.引用其他message类

在同一个文件中,可以直接引用定义过的message类型,在同一个项目中,可以用import来导入其它message类型。

import "myproject/other_protos.proto";
6.双向流式RPC

双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:比如,服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替的读取和写入消息,或者其他读写的组合。每个流中的消息顺序被预留。你可以通过在请求和响应前加 stream 关键字去制定方法的类型

4.数据类型对比

.proto类型 Java 类型 C++类型 备注
double double double
float float float
int32 int int32 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint32。
int64 long int64 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint64。
uint32 int[1] uint32 Uses variable-length encoding.
uint64 long[1] uint64 Uses variable-length encoding.
sint32 int int32 使用可变长编码方式。有符号的整型值。编码时比通常的int32高效。
sint64 long int64 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效。
fixed32 int[1] uint32 总是4个字节。如果数值总是比总是比228大的话,这个类型会比uint32高效。
fixed64 long[1] uint64 总是8个字节。如果数值总是比总是比256大的话,这个类型会比uint64高效。
sfixed32 int int32 总是4个字节。
sfixed64 long int64 总是8个字节。
bool boolean bool
string String string 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
bytes ByteString string 可能包含任意顺序的字节数据。
推荐阅读