gRPC整理
背景
RPC
RPC是远程过程调用(Remote Procedure Call)的缩写。它是一种计算机通信协议,使得程序可以请求另一个进程或者计算机上的服务,就像调用本地的函数一样,从而实现分布式系统之间的交互和通讯。RPC可以大大简化分布式系统的开发,提高系统的可维护性和可扩展性。一个比较常见的用法,RPC下载器,例如:aria2、Motrix,可以用来帮助下载一些限速网盘的资源。
优点
抽象屏蔽:RPC框架可以屏蔽底层的网络通信细节,使得远程调用就像本地调用一样简单。
可扩展性:RPC框架可以支持多种协议和编码方式,可以适应不同场景的需求,同时也可以方便地添加新的功能和服务。
可靠性:RPC框架通常会提供各种机制来保证通信的可靠性,如超时重试、错误处理等。
高效性:RPC框架通常使用二进制协议和高效的序列化方式,可以大大减少网络传输的数据量,提高系统的性能。
语言无关性:RPC框架可以支持多种编程语言,使得不同语言的程序可以方便地进行交互和通讯。
缺点
依赖网络:RPC需要通过网络进行通信,因此对网络的稳定性和延迟要求比较高。
难以调试:由于RPC是跨进程或者跨计算机的调用,因此调试起来比较困难,需要使用一些特殊的工具和技术。
数据格式限制:RPC框架通常会限制数据的格式和大小,如果需要传输大量的数据或者复杂的数据结构,可能会导致性能问题。
安全性问题:RPC通常不会提供加密和认证等安全机制,需要在应用层进行处理,否则容易受到攻击。
可靠性问题:RPC框架虽然提供了一些机制来保证通信的可靠性,但仍然可能出现通信失败、丢失消息等情况,需要应用程序自己处理。
gRPC
概括
gRPC是Google开源的一种高性能、通用的远程过程调用(RPC)框架,基于Protocol Buffers序列化协议进行数据传输。
优点
高性能:gRPC采用基于HTTP/2的二进制传输协议,可以实现双向流、头部压缩和多路复用等特性,提高了网络传输的效率和性能。
多语言支持:gRPC支持多种编程语言,包括C++、Java、Python、Go、Ruby等,可以方便地构建跨语言的分布式系统。
自动生成代码:gRPC可以根据服务定义文件自动生成客户端和服务器端的代码,大大简化了开发过程。
可扩展性:gRPC支持多种负载均衡算法和服务发现机制,可以适应不同场景的需求。
安全性:gRPC支持TLS加密和认证等安全机制,保障通信的安全性。
易于使用和维护:gRPC提供了丰富的文档和工具链,使得开发和维护分布式系统变得更加容易。
支持多种序列化协议:gRPC支持多种序列化协议,包括Google开发的Protocol Buffers序列化协议和JSON等,可以根据实际需求选择最适合的序列化方式。
支持流式数据传输:gRPC支持双向流、客户端流和服务器端流等多种流式数据传输方式,可以满足不同的业务需求。
缺点
不支持RESTful API:gRPC不支持基于HTTP的RESTful API,无法与现有的RESTful API进行兼容和集成。
不支持浏览器端:gRPC目前不支持Web浏览器端,因为浏览器不支持HTTP/2协议。
依赖Protocol Buffers:gRPC默认使用Google开发的Protocol Buffers序列化协议,如果需要使用其他的序列化协议,则需要自行实现。
难以调试:由于gRPC采用二进制协议,数据的传输和解析都是以二进制形式进行的,对于调试和排错带来了一定的困难。
安全性依赖于TLS:虽然gRPC支持TLS加密和认证等安全机制,但这些机制都依赖于TLS协议,如果TLS协议本身存在漏洞或被攻击,则会影响gRPC的安全性。
Protobuf介绍
概括
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
proto2
// 表示正在使用proto2命令
syntax = "proto2";
//包声明 test
//也可以声明为二级类型,例如a.b,表示a类别下b子类别
//如果另一个文件引这个包,要用这里的东西,需要使用test.xxx
package test;
//每句话都要加分号结尾,import要带上.proto
//引一个没用的包,会警告,不报错
import "A.proto";
import "google/protobuf/empty.proto";
//给go语言用的,如果其他文件引用了这个文件,那么生成go代码之后,会自动按照分号前的目录创建出目录,并且添加上引用
option go_package = "github.com/test/pb;pb";
message helloworld {
required int32 id = 1; //不能用int,必须指定到具体的位数,仅支持32位以上,详细支持的类型可查看proto官网文档
optional bool boo = 2; //required是必须的,没有会报错,optional是可选的,可以没有
repeated string str = 3; //相当于 []string,是复数的意思
map<string, string> ma = 4; //gpt说proto2不支持map,但是实际我用工具生成出来的proto,是支持的,生成代码也没有报错
}
service worldhello {
rpc testWorldHello(google.protobuf.Empty) returns (helloworld); //参数和返回值必须有且只有一个,不想要可以用google.protobuf.Empty
}proto3
//和proto2很像,以下仅解释不同的地方
syntax = "proto3";
package test;
import "A.proto";
import "google/protobuf/empty.proto";
option go_package = "github.com/test/pb;pb";
message helloworld {
int32 id = 1; //全都是可选的,没有optional和required了
bool boo = 2;
repeated string str = 3;
map<string, string> ma = 4;
}
service worldhello {
rpc testWorldHello(google.protobuf.Empty) returns (helloworld);
}protoc 命令
注意:对于根据proto生成go代码的场景,proto2生成的go代码,所有字段全都是指针;proto3生成的go代码,结构体全是指针,结构体内的字段是正常的。
-I 或 --proto_path= 指定引用的proto文件路径的
--cpp_out=,--python_out= 指定生成文件的位置和生成的语言的。protoc默认支持13种语言,
go_out对应protoc-gen-go插件;
go-grpc_out对应protoc-gen-go-grpc插件;
*_out对应protoc-gen-*插件;部分语言,如Go,需要手动安装一下插件,
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@版本 go install google.golang.org/grpc/cmd/protoc-gen-go@版本对于版本较老的protoc-gen-go,命令如下:
protoc -I $protodir --go_out=plugins=grpc:./genproto/ yourfile.proto对于版本较新的protoc-gen-go,命令如下:
protoc -I $protodir --go_out=./genproto/ --go-grpc_out=./genproto/ yourfile.proto新版本会生成两个文件,一个结构,一个方法;老版本只有一个文件,结构和方法在一起。
通过protoc命令,可以同时生成出Client和Server端代码。不同进程可以依据生成出的代码完成交互。
附录
gpt4说的proto2和proto3的区别
Protocol Buffers(ProtoBuf)是 Google 开发的一种数据序列化协议,广泛用于网络通信和数据存储。ProtoBuf 有两个主要的版本:
proto2和proto3。以下是两者间的一些主要区别:
默认值:在
proto2中,字段可以通过optional关键字指定为可选的,并可以为字段指定默认值。在proto3中,所有字段都是可选的,并且不能显式地为字段指定默认值。非指定的字段将使用其类型的零值。字段存在性检查:
proto2支持HasField方法来检查一个字段是否被设置。proto3不支持这个特性,因为所有字段都是可选的,并且总是有值(如果没有显示设置,就是类型的零值)。字段标记:
proto2支持required、optional和repeated标记。proto3只支持repeated标记,所有未标记的字段都是可选的。枚举类型:
proto3的枚举类型必须从 0 开始定义,且第一个值必须为零值。proto2对此没有要求。兼容性:
proto3是为了更简单和更好的跨语言兼容性而设计的。虽然它移除了一些proto2的特性,但是也增加了一些新的特性,如Any类型和map字段。语言支持:
proto3提供了更广泛的语言支持,包括 Java、C++、Python、Go、C#、Ruby、JavaScript 等。这两个版本在使用上有一些不同,选择哪个版本需要根据你的具体需求和偏好来决定。
gpt4总结的protoc-gen-go和protoc-gen-go-grpc的区别
这个 StackOverflow 的问题主要关注的是
protoc-gen-go和protoc-gen-go-grpc两个protoc插件之间的区别。以下是这两个插件的主要区别:
protoc-gen-go:这个插件用于生成 Protocol Buffers 的 Go 代码。它根据.proto文件生成消息类型和服务接口的定义。
protoc-gen-go-grpc:这个插件用于生成 gRPC 的 Go 代码。它根据.proto文件中的服务定义生成实现 gRPC 服务和客户端所需的代码。在早期,
protoc-gen-go插件同时生成 Protocol Buffers 和 gRPC 的代码。然而,自protoc-gen-gov1.20.0 开始,生成 gRPC 代码的功能被移除。生成 gRPC 代码现在需要使用protoc-gen-go-grpc插件。因此,如果你的
.proto文件中只有消息类型的定义,你只需要protoc-gen-go插件。如果你的.proto文件中还包含服务定义,并且你需要生成 gRPC 服务和客户端的代码,你需要同时使用protoc-gen-go和protoc-gen-go-grpc插件。例如,你可以通过以下命令来生成代码:
protoc --go_out=. --go-grpc_out=. yourfile.proto在这个命令中,
--go_out参数用于生成 Protocol Buffers 的代码,--go-grpc_out参数用于生成 gRPC 的代码。.表示生成的代码的输出目录,yourfile.proto是你的.proto文件。
参考文档
终于有人把tcp、http、rpc和grpc总结完整了 - 知乎 (zhihu.com)
Protobuf通信协议详解:代码演示、详细原理介绍等 - 知乎 (zhihu.com)
proto参数区分之package和option go_package-CSDN博客
Go - 关于 protoc 工具的小疑惑 - 知乎 (zhihu.com)
Differences between protoc-gen-go and protoc-gen-go-grpc - Stack Overflow