RPC(四)| 来自Google的gRPC
gRPC是Google开源的一款RPC框架,跟具体语言无关,以protobuf作为IDL,通过protoc来编译框架代码。gRPC的Java实现的底层网络库是基于Netty开发而来,其Go实现是基于net库。
先说下Protobuf,它是一个纯粹的展示层协议,可以和各种传输层协议一起使用;Protobuf的文档也非常完善。 Protobuf具备了优秀的序列化协议所需的众多典型特征:
- 标准的IDL和IDL编译器,这使得其对工程师非常友好。
- 序列化数据非常简洁,紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。
- 解析速度非常快,比对应的XML快约20-100倍。
- 提供了非常友好的动态库,使用非常简介,反序列化只需要一行代码。
- 更好的兼容性,很好的支持向下或向上兼容。
数据类型
- double: 浮点数
- float: 单精度浮点
- int32: int类型,使用可变长编码,编码负数不够高效,如果有负数那么使用sint32
- sint32: int类型,使用可变长编码, 有符号的整形,比通常的int32高效;
- uint32: 无符号整数使用可变长编码方式;
- int64 long long , 使用可变长编码方式。编码负数时不够高效——如果有负数,可以使用sint64;
- sint64 long long 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效;
- uint64: 无符号整数使用可变长编码方式;
- fixed32 : 总是4个字节。如果数值总是比总是比2^28大的话,这个类型会比uint32高效。
- fixed64: 总是8个字节。如果数值总是比总是比2^56大的话,这个类型会比uint64高效。
- sfixed32: 总是4个字节。
- sfixed64: 总是8个字节。
- bool:bool值
- string: 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
- bytes: 可能包含任意顺序的字节数据。类似java的ByteString以及 c++ string;
enum包
# 定义enum
enum Direction {
LEFT = 1;
RIGHT = 2;
UP = 3;
DOWN = 4;
};
IDL文件举例
message Address
{
required string city=1;
optional string postcode=2;
optional string street=3;
}
message UserInfo
{
required string userid=1;
required string name=2;
repeated Address address=3;
}
关于ProtoBuf的详细解析,参考这篇文章:https://blog.csdn.net/carson_ho/article/details/70568606
ProtoBuf文档:https://www.grpc.io/docs/
gRPC为什么选择Http2
gRPC选择HTTP/2作为传输协议的原因主要包括兼容性、性能和设计目标。 gRPC是基于HTTP/2实现的,因为HTTP/2协议提供了多路复用、二进制传输等特性,能够满足gRPC的设计需求和性能要求。
首先,兼容性是gRPC选择HTTP/2的一个重要原因。HTTP/2协议已经成为许多现代web服务器的标准协议,包括Nginx等。这使得基于HTTP/2的gRPC能够与现有的基础设施兼容,减少了部署和维护的成本。
其次,性能方面,HTTP/2提供了多路复用和二进制传输等特性,这些特性能够显著提高数据的传输效率,减少延迟。gRPC需要高效的数据传输来支持其高性能的RPC调用,HTTP/2的这些特性正好满足了这一需求。
最后,设计目标上,gRPC的设计目标是支持跨语言、跨环境的RPC调用,HTTP/2的支持使得gRPC能够在不同的平台上运行,包括物联网设备、手机、浏览器等。此外,HTTP/2还支持流控和流式处理,这些都是gRPC设计中的重要特性。
参考阅读:
https://zhuanlan.zhihu.com/p/161577635
https://juejin.cn/post/7249522846211801147
gRPC vs Restful API
gRPC和Restful API
都提供了一套通信机制,用于server/client
模型通信,而且它们都使用http
作为底层的传输协议(严格地说,gRPC使用的http2.0
,而Restful API
则不一定)。不过gRPC还是有些特有的优势,如下:
- gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。
- 通过protobuf可以将数据序列化为二进制编码,减少传输的数据量,大幅提高性能。
- gRPC可以方便地支持流式通信(通过http2.0可以使用streaming模式)。
使用场景
- 需要对接口进行严格约束的情况。
- 对于性能有更高的要求时。
通常我们不会去单独使用gRPC,而是将gRPC作为一个部件进行使用,这是因为在生产环境,我们面对大并发的情况下,需要使用分布式系统来去处理,而gRPC并没有提供分布式系统相关的一些必要组件。而且,真正的线上服务还需要提供包括负载均衡,限流熔断,监控报警,服务注册和发现等等必要的组件。
安装gRPC
gRPC的中文文档参考:http://doc.oschina.net/grpc?t=56831
Go版本的gRPC开源项目地址:https://github.com/grpc/grpc-go
go get -u google.golang.org/grpc
安装protoc
编译器
gRPC默认使用ProtoBuf协议,需要借助protoc
来为不同语言平台编译目标源代码。
首先,安装protoc
编译器,通过这个https://github.com/protocolbuffers/protobuf/releases地址下载,选择适合自己操作系统的版本。下载后要把二进制protoc
放在自己的$PATH/bin
目录中,确保可以在终端执行
其次,因为ProtoBuf起初不支持Go语言,所以我们还得安装一个生成Golang代码的工具。安装方式也非常简单,通过如下代码即可:
go get -u github.com/golang/protobuf/protoc-gen-go
注意:有可能说还是找不到protoc-gen-go
命令,请到$GOPATH\bin\bin
目录中看看,如果有就把它放入上一个目录。
假设我们有一个配置文件user.proto
,那么我们在终端下cd到存放user.proto
文件的目录,执行如下代码即可生成对应的Golang代码
protoc --go_out=. user.proto
--go_out=.
表示输出Golang代码文件到当前目录下,生成的文件名是user.pb.go
,规则就是filename.pb.go
。
使用gogoproto三方库
有一个第三方库,编解码性能远高于官方标准库,他就是:github.com/gogo/protobuf
,但这个库已经不维护了,推荐使用官方库。
|
|
如果想体验这个三方库的性能,可能需要用下面的配套工具生成代码。
protoc --gogofaster_out=. user.proto
gRPC示例1
编写ProtoBuf描述文件,定义接口和数据类型;然后编译:
|
|
定位到grpc_demo/pro
目录,执行命令(一定要加plugins=grpc的参数,否则无法正确生成RPC相关的代码):
protoc --go_out=plugins=grpc:. spider.proto
注意这里有个参数配置是Go语言平台特有的,否则编译的时候可能报错:
option go_package = ".;pro";
# . 表示生成的go文件的存放地址,会自动生成目录的;这里指定当前目录
# pro 表示生成的go文件所属的包名;这里指定 pro
当前项目grpc_demo
的目录结构如下:
├─client
│ client.go
├─pro
│ spider.pb.go
│ spider.proto
└─server
server.go
server/server.go
的代码:
|
|
client/client.go
的代码:
|
|
分别启动server和client,就会在client的控制台中看到百度的首页html代码了。
gRPC示例2
下面是一个gRPC的官方示例。
IDL文件pro/helloworld.proto
:
syntax = "proto3";
option go_package = ".;pro";
package pro;
message HelloRequest {
string name = 1;
}
message HelloReplay {
string message = 1;
}
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReplay) {}
}
下面的命令编译IDL文件,生成gRPC框架代码:
protoc --go_out=plugins=grpc:. helloworld.proto
服务器端:
|
|
客户端代码:
|
|
运行结果如下:
// server端
2021/01/25 22:53:11 Received Name: chende
// client端
2021/01/25 22:53:11 Greeting: Hello chende
如何启动gRPC压缩传输
大家用网络抓包工具查看上面的例子,会发现在HTTP2.0协议上走的是明文的内容,根本没有启动协议压缩功能。如何压缩传输呢?其实很简单,只需要2步就好了。
第一步:在服务端和客户端import中都要加入_ "google.golang.org/grpc/encoding/gzip"
,因为gzip.go
文件中默认有对压缩算法的初始化设置。
|
|
第二步:在客户端发送请求的时候,指定(CallOption)压缩传输标记即可。
c.SayHello(ctx, &pro.HelloRequest{Name: name}, grpc.UseCompressor(gzip.Name))
就拿上面的示例2来说,我故意把发送的内容复制重复N遍,改造成发送原文5184个字节。
未压缩,抓包截图:
启用gzip压缩,抓包截图:
看到没有,5263字节直接变成了152字节。看到压缩的威力了吗?
参考阅读:
https://www.zhihu.com/question/30027669/answer/2872058473
https://blog.csdn.net/zhoupenghui168/article/details/130923516
(完)
- 原文作者: 闪电侠
- 原文链接:https://chende.ren/2021/01/23215755-004-rpc-grpc.html
- 版权声明:本作品采用 开放的「署名 4.0 国际 (CC BY 4.0)」创作共享协议 进行许可