grpc教程(三)grpc的底层原理
grpc构建在两个快速高效的协议之上,也就是protocol buffers和http/2。
protocol buffers是一个语言中立,平台无关的数据序列化协议。当序列化完成后,该协议会生成二进制载荷,这种载荷波json载荷更小,并且是强类型的。
HTTP/2是http的第二个主版本,完全多路复用意味着http/2可以在tcp连接上并行发送多个数据请求。
01
—
通过网络实现rpc流程
以下是grpc调用时一个简单的流程:
1.客户端进程通过protoc生成的编码的stub,并调用具体方法。
2.客户端用已编码的消息创建HTTP POST请求。
在grpc中,所有的请求都是HTTP/POST请求,并且content-type前缀为application/grpc,要调用的远程方法是以单独的HTTP头信息发送的。
3.HTTP请求通过网络发送到服务器端。
4.服务端接收到消息后检查头信息,从而确定需要调用的服务方法,然后将消息传递给服务器处理。
5.服务器将消息字节解析成特定语言的数据结构。
6.服务器骨架对解析后的方法进行本地调用。
02
—
使用protocol buffers编码
使用protocol buffers编码消费
grpc使用proto文件编写服务定义,使用protocol buffers定义服务。proto语法有proto2和proto3版本,它们之间还是有区别的。
比如制定变量规则,在 proto3 中,可以给变量指定以下两个规则:
singular:0或者1个,但不能多于1个。
repeated:任意数量(包括0)当构建 message 的时候,build 数据的时候,会检测设置的数据跟规则是否匹配。
在proto2中,规则为:
required:必须有一个
optional:0或者1个
repeated:任意数量(包括0)
例子:
// 指定使用proto3,如果不指定的话,编译器会使用proto2去编译
syntax = "proto3"; //[proto2|proto3]
message SearchRequests {
// 定义SearchRequests的成员变量,需要指定:变量类型、变量名、变量Tag
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
在创建消息实例的过程时,对应的字节内容会包含一个用于字段的标识符,随后是其编码的值。在字段的标识符也被称为标签(tag)。
标签由两个值构成:字段索引和线路类型。
字段索引就是在proto文件中定义消息时,为每个消息字段所设置的唯一数字。线路类型是基于字段类型,也就是能够为字段输入值的数据类型。线路类型会提供信息来确定值,会占3位。
protocol buffers支持各种字段类型,有些字段类型有不同的编码机制。比如int32,int64,uint32,uint64,sint32(高效编码负数),sint64(高效编码负数)
基于长度前缀的消息分帧
消息分帧会构建消息和通信,以便于目标受众很容易提取信息,对于grpc使用了长度前缀分帧的消息分帧技术。
长度前缀分帧是指在写入消息本身前,根据消息的proto定义写入长度信息来表明每条信息的大小。在grpc中每条消息有额外的4字节用来设置其大小,也就意味着grpc通信可以处理大小不超过4GB的所有消息。
所以一旦更改了proto消息中的字段类型,其实会影响整个消息队列的,客户端接收到的消息不仅仅是单个字段不可用,而是整个消息都因错乱而解析不了。
因此使用grpc时,一定要保持协议一致。
03
—
基于http/2的grpc
在http/2中客户端和服务器所有通信都是通过一个tcp连接完成的,这个连接可以传送任意数量的双向字节流。
一些基本概念:
流:在一个建立的连接上的双向字节流,一个流可以携带一条或多条消息。
帧:http/2中最小的通信单元,每一帧都包含一个帧头,它至少要标记该帧所属的流。
消息:完整的帧序列,映射为一条逻辑上的http消息。由一帧或多帧组成。这样的话,允许消息进行多路复用,客户端和服务端能将消息分解成独立的帧,交叉发送它们,然后在另一端进行重新组合。
http/2的基本解释(此处来源网络):
HTTP/2主要是为了解决现HTTP 1.1性能不好的问题才出现的。当初Google为了提高HTTP性能,做出了SPDY,它就是HTTP/2的前身,后来也发展成为HTTP/2的标准。
HTTP/2兼容HTTP 1.1,例如HTTP Method,Status code,URI以及大部分Header Fields。
HTTP/2通过以下方法减少延迟,用来改进页面加载的速度,
HTTP Header的压缩采用的是HPack算法。
HTTP/2的Server Push,非常重要的一个特性。
请求的pipeline。
修复在HTTP 1.x的队头阻塞问题。
在单个TCP连接里多工复用请求。
HTTP/2支持HTTP 1.1里的大部分use case,例如桌面浏览器、移动浏览器、Web API、Web Server、代理服务器、反向代理服务器、防火墙和CDN等。