gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf

目录

一、gRCP - 面向未来的第二代 RPC 技术

1.1、gRPC 简介

1.1.1、gRPC 是个啥?

1.1.2、gRPC 核心设计思路

1.1.3、gRPC 和 ThriftRPC 区别

1.1.4、为什么使用 gRPC?(好处)

1.2、HTTP2.0 协议

1.2.1、回顾 HTTP1.0 和 HTTP1.1

1.2.2、HTTP2.0 协议

1.3、Protocol Buffers(Protobuf)

1.3.1、protobuf 是什么

1.3.2、安装 Protobuf 编译器

1.3.3、protobuf 语法


一、gRCP - 面向未来的第二代 RPC 技术


1.1、gRPC 简介

1.1.1、gRPC 是个啥?

gRPC 是 Google 开源的一个高性能的 RPC 框架,高效实现进程间通信。Studdy Google 内部的 RPC 演化而来,2015 正式开源. 云原生时代是一个 RPC 标准.

1.1.2、gRPC 核心设计思路

对于远程调用的的设计思路,一般都是以下四个方面:

  1. 网络通信:gRPC 自己封装网络通信的部分,并提供多种语言的封装(C、Java[Nerry]、GO).
  2. 协议:gRPC 使用 HTTP2 传输数据(二进制数据内容),支持双工(双向流)连接的多路复用.
  3. 序列化:基于 Protobuf 的序列化方式,时间效率和空间效率都是 JSON 的 3~5 倍.
  4. 代理的创建:让调用者像调用本地方法一样,去调用远端的服务方法.

1.1.3、gRPC 和 ThriftRPC 区别

共同点:支持异构语言的 RPC.

不同点:

  1. 网络通信:ThriftRPC 使用 TCP 专属协议.  gRPC 使用 HTTP2 协议.
  2. 性能方面:ThriftRPC 高于 gRPC.
  3. 应用广度:gRPC 大厂背书(Google),云原生时代和其他组件合作很顺利,因此应用更广泛.

1.1.4、为什么使用 gRPC?(好处)

  1. 高效:基于 HTTP2 协议,传输二进制数据内容,又基于 Protobuf 实现序列化,高效的进行进程间通信.
  2. 支持多种语言:原生支持 C、GO、Java 实现。C语言版本上可扩展 C++、C#、NodeJS、Python、Ruby、PHP.
  3. 跨平台:支持多平台运行 linux、Android、IOS、MacOS、Windows.
  4. 大厂背书:Google 力推.

1.2、HTTP2.0 协议

1.2.1、回顾 HTTP1.0 和 HTTP1.1

HTTP1.0 协议:

  • 请求响应模式:一个请求对应一个响应.
  • 短链接协议:无状态协议,客户端不认识服务器,反之也一样,可引入 Session - Cookie 机制解决.
  • 传输数据:文本结构.
  • 单工:无法实现服务端推送机制,要实现必须让客户端 "轮询".

HTTP1.1 协议:

  • 请求响应模式:一个请求对应一个响应.
  • 有限长连接:可升级为 WebSocket 协议,实现服务器向客户端的消息推送机制.
  • 传输数据:文本结构.
  • 双工:服务器可对客户端进行消息推送.

可以看出,HTTP1.x 协议的共性如下:

  • 传输数据都是文本格式,可读性好,但是效率差.
  • 本质上 HTTP1.x 协议无法实现双工通信.
  • 关于资源请求,需要发送多次请求,建立多个连接才可以完成.  例如一般发送一个请求第一次请求到的是一个 HTML 格式的数据,然后还需要继续发两次请求,以异步的方式请求 JS 和 CSS 文件(网络通信也是需要开销的,三次握手、四次挥手......).

1.2.2、HTTP2.0 协议

  • 二进制通信:HTTP2.0 协议是一个二进制协议,效率高于 HTTP1.x,但是可读性较差.
  • 实现双工通信:服务器可对客户端进行消息推送.
  • 实现了多路复用机制:一个连接可以请求多个数据.

具体的通信过程,首先要明确 HTTP2.0 协议以下三个重要概念:

  1. 数据流(Stream):客户端和服务器之间传输数据的通道(一个连接中可以有多个数据流).
  2. 消息(message):一个消息中就包含了多个帧.
  3. 帧(frame):就是一些具体的请求头,请求体信息.

如下图:

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf_第1张图片

Ps:

  1. 数据流的优先级:可以通过权重的方式设置的,用来限制的不同流的传输顺序.
  2. 流控效果:client 发送数太快了,server 处理不过来,就会通知 client 暂停数据的发送.

1.3、Protocol Buffers(Protobuf)

1.3.1、protobuf 是什么

protobuf 是一种与编程语言无关,与具体平台无关(任意操作系统)的序列化工具,自定义了中间语言(IDL),使得数据在 client 和 server 中进行 RPC 传输.

Ps:protobuf 有两个版本(proto2 和 proto3),主流应用都是 proto3.

1.3.2、安装 Protobuf 编译器

protobuf 安装编译器的目的就是为了把 protobuf 的 IDL 语言,转化成某一种开发语言,例如 Java.

a)下载地址:Releases · protocolbuffers/protobuf · GitHub

新版没有提供 windows 版本的安装包,可以去老版本找到,例如 Protocol Buffers v23.1

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf_第2张图片

b)下载好后解压,配置环境变量 path

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf_第3张图片

c)打开终端,输入 protoc --version,检查是否配置成功(查看版本)

1.3.3、protobuf 语法

a)文件格式:文件都是以 proto 为后缀,例如 UserService.proto、OrderService.proto.

b)版本设定:使用 proto3 即可

syntax = "proto3";

c)注释:// 表示单行注释,/* */ 表示多行注释.

d)Java 语言相关

//protobuf 生成的 Java 代码,是一个源文件还是多个?false 表示一个(一般开发就用 false)
option java_multiple_files = false;

//指定 protobuf 生成的类,放置在哪个包中
option java_package = "com.cyk";

//指定 protobuf 生成的外部类的名字(用来管理内部类[内部类才是真正开发使用的])
option java_outer_classname = "UserService";

e)逻辑包:protobuf 对文件内容的管理(作为 Java 工程师,可以不用逻辑包,用 Java 包就够了,逻辑包了解就行)

package xxx

f)导入:假设有 A.proto 和 B.proto 文件,现在需要在 B.proto 文件中引入 A.proto 文件的内容,就需要在 B.proto 文件中导入 A.proto.

// 在 B.proto 文件中导入 A.proto 文件
import xxx/A.proto

g)枚举:枚举值必须是从 0 开始.

enum SEASON {
  SPRING = 0;
  SUMMER = 1;
}

h)数据类型:就是消息中定义的数据类型(我们主要关心 .proto 对应的 Java 类型).

以下列表来自官网:Language Guide (proto 3) | Protocol Buffers Documentation

.proto Type C++ Type Java/Kotlin Type[1] Python Type[3] Go Type Ruby Type C# Type PHP Type Dart Type
double double double float float64 Float double float double
float float float float float32 Float float float double
int32 int32 int int int32 Fixnum or Bignum (as required) int integer int
int64 int64 long int/long[4] int64 Bignum long integer/string[6] Int64
uint32 uint32 int[2] int/long[4] uint32 Fixnum or Bignum (as required) uint integer int
uint64 uint64 long[2] int/long[4] uint64 Bignum ulong integer/string[6] Int64
sint32 int32 int int int32 Fixnum or Bignum (as required) int integer int
sint64 int64 long int/long[4] int64 Bignum long integer/string[6] Int64
fixed32 uint32 int[2] int/long[4] uint32 Fixnum or Bignum (as required) uint integer int
fixed64 uint64 long[2] int/long[4] uint64 Bignum ulong integer/string[6] Int64
sfixed32 int32 int int int32 Fixnum or Bignum (as required) int integer int
sfixed64 int64 long int/long[4] int64 Bignum long integer/string[6] Int64
bool bool boolean bool bool TrueClass/FalseClass bool boolean bool
string string String str/unicode[5] string String (UTF-8) string string String
bytes string ByteString str (Python 2)
bytes (Python 3)
[]byte String (ASCII-8BIT) ByteString string List

i)消息(Message):定义了客户端和服务器一次请求和相应的具体格式

//1.Ps: 编号范围是[1, 2^29-1],但是 19000~19999 不能使用,因为他是 protobuf 自己保留的
message LoginRequest {
   string username = 1;
   string password = 2;
   int32 age = 3;
}

//2.singular: 表示这个字段的值只能有 0 个或 1 个,也就是 null 或者是一个具体的值
//repeated: 表示 Java 中的 List 类型
message LoginResponse {
  string content = 1;
  repeated string status = 2;
}

//3.消息可以嵌套
message LogoutRequest {
  message User {
    int64 userId = 1;
    string username = 2;
  }

  string aaa = 1;
  string bbb = 2;
  User user = 3;
}

//4.可以使用其他消息的属性
message Test1Message {
  string aaa = 1;
  LogoutRequest.User bbb = 2;
}

//5.oneof 表示其中一个(实际开发中用的很少)
message Test2Message {
  oneof test_oneof {
    string aaa = 1;
    string bbb = 2;
  }
}

j)服务:用来定义服务接口,一个接口中可以有多个服务方法(gRPC 的 4 个服务方式下一章再展开讲~).

语法如下:

service 自定义接口名 {
  rpc 自定义方法名(参数类型) returns(返回值类型) {}
  //......
}

例如: 

message LoginRequest {
   string username = 1;
   string password = 2;
   int32 age = 3;
}
message LoginResponse {
  string content = 1;
  repeated string status = 2;
}


service UserService {
  rpc login(LoginRequest) returns(LoginResponse) {}
}

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf_第4张图片

你可能感兴趣的:(gRPC,-,面向未来的第二代,RPC,技术,rpc,网络协议,网络)