Skip to main content

gRPC

gRPC

gPRC是一个由Goggle开源、基于HTTP/2、可跨语言的高性能RPC框架,它使客户端和服务器应用程序能够透明地进行通信,并简化了构建分布式系统的过程。

gRPC基于HTTP/2协议进行传输,使用Protocol Buffers(Protobuf)作为接口定义语言(IDL)和数据序列化协议,所有的数据传输都会在底层进行序列化及反序列化,而无需手动进行,解决了使用RPC原生开发的一些痛点。

gPRC

gRPC版本

  1. grpc for C,支持编写C、C++、C#、NodeJS、Python、Ruby等。
  2. grpc-java for Java。
  3. grpc-go for Go。

Protobuf基础

Protobuf即Protocol Buffers,是Google成熟的开源的数据结构序列化机制,是一种序列化反序列化协议,类似于JSON、XML的数据结构化。

在传输数据的过程中,使用Protobuf代替JSON等协议,称为Proto RequestProto Response

优缺点
  1. 序列化与反序列化效率高。
  2. 可自动序列化和反序列化。
  3. 压缩性能强。相比之下,JSON基本没什么压缩。
  4. 传输速度快。由于压缩体积小,因此传输很快。
  5. 加密性强。一般不去反序列化是看不到原始数据的。
  6. 跨平台跨语言。支持多种操作系统,提供相应的程序。
  7. 轻量级,维护性好。有单独的.proto文件。

因此,可在均支持Protobuf的语言之间使用Protobuf,其他情况可选择考虑使用JSON。

安装与配置
brew install protobuf@3

protoc --version

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
// go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
proto文件
  1. .proto文件能帮助你使用简单的代码生成复杂的Go文件,服务端和客户端只需定义一套数据就可被定义成Go语言所认识的代码。
  2. .proto文件中最主要的是定义数据,其次才是定义服务。
  3. .proto文件需要进行编译才能生成真正的Go文件,生成的文件名为xxx.pb.go
// 指定语法版本
syntax = "proto3";

// 每行的末尾必须要有分号,否则会报错

// Go语言中的package就是文件夹

/**
* ./ 表示编译后生成的目录放到哪个目录
* proto 表示编译后文件的包名
*/
option go_package = "./;proto";
文件编译
protoc -I . info.proto --go_out=plugins=grpc:.
// protoc -I . info.proto --go-grpc_out=.

// 编译后会生成`xxx.pb.go`Go源码文件。
编码结果对比
package main

import (
__ "basic3/proto"
"encoding/json"
"fmt"
"google.golang.org/protobuf/proto"
)

func main() {
phInfo := __.Person{
Id: 1,
Name: "Tom",
IsMarriage: true,
}

phResp, _ := proto.Marshal(&phInfo)

fmt.Println(phResp)
fmt.Println(string(phResp))
}
/**
[8 1 18 3 84 111 109 24 1]
Tom
*/

可见,Protobuf相比于json序列化后体积更小,且加密性更好。

案例

计算器
syntax = "proto3";
option go_package="./;proto";

// proto中的枚举
enum CalculatorType {
// 必须从0开始
PLUS = 0;
MINUS = 1;
MULTIPLY = 2;
DIVIDE = 3;
}

// 请求
message CalculatorRequest {
int32 num1 = 1;
int32 num2 = 2;
CalculatorType type = 3;
}

// 响应
message CalculatorResponse {
int32 num1 = 1;
int32 num2 = 2;
CalculatorType type = 3;
int32 result = 4;
}

// 定义服务端的接口
service Calculator {
// 要调用的方法
// rpc Method(Request) returns (Response)
rpc Calculator(CalculatorRequest) returns (CalculatorResponse);
}
跨语言

grpc支持跨语言通信,以下以Node为例实现一个TodoList:Go作为服务端,而Node作为客户端并给前端提供接口:

syntax = "proto3";
option go_package = "./;proto";

message AddingTodoRequest {
string content = 1;
}

message TogglingTodoRequest {
int64 id = 1;
}

message RemovingTodoRequest {
int64 id = 1;
}

message TodoResponse {
int64 id = 1;
string content = 2;
bool completed = 3;
}

service TodoList {
rpc AddTodo (AddingTodoRequest) returns (TodoResponse);
rpc ToggleTodo (TogglingTodoRequest) returns (TodoResponse);
rpc RemoveTodo (RemovingTodoRequest) returns (TodoResponse);
}

gRPC通信模式

简单模式

Simple RPC Mode,一次请求与一次响应。

服务端数据流模式

Server-Side Streaming RPC Mode,服务端向客户端持续性传输数据流。

/*
本案例以流式传输一张图片为例:
1. 客户端向服务端发起请求。
2. 服务端针对请求持续不断地进行流式传输,直到传输完毕。
3. 客户端持续不断地接收数据,并将最终的数据写入一个文件中,生成一张图片。
4. 流式传输完毕。
*/
客户端数据流模式

Client-Side Streaming RPC Mode,客户端向服务端持续性传输数据流。

客户端数据流传输与服务端模式正好相反:

syntax = "proto3";
option go_package = "./;proto";

message FileRequest {
string slice = 1;
float progress = 2;
}

message FileResponse {
string filename = 1;
}

service File {
rpc PostStream (stream FileRequest) returns (FileResponse);
}
双端数据流模式

Bidirectional Streaming RPC Mode,客户端与服务端双向持续性传输数据流。