gRPC调研: 基于HTTP2的gRPC框架实现

11 Feb 2020 - Sindweller-ch

gRPC简介

gRPC是由Google主导开发、可以在任何环境中运行的开源高性能RPC(远程过程调用)框架,基于HTTP2和Protobuf实现。gRPC是跨语言的RPC框架,采用了IDL来描述数据类型和接口,使用编译器编译出特定语言的代码从而实现跨语言的RPC。

什么是RPC?

假设有两台服务器A、B,应用a部署在A服务器上,想要调用B服务器上应用b提供的函数/方法,由于不在同一个内存空间,不能直接调用,此时需要网络来表达调用的语义和传达调用的数据。可用于多台机器组成的集群上部署应用。

RPC的解决问题的过程如下:

可以理解为,RPC就是从一台机器(Client)上通过传参的方式调用另一台机器(Server)上的一个方法(统称为服务)并得到返回的结果。RPC会隐藏底层的通讯细节,即不需要直接处理Socket或HTTP通讯,它是一个请求响应模型:客户端发起请求,服务器返回响应,这是一种类似HTTP的工作方式,在形式上类似调用本地方法,只不过依靠网络可以调用远程的方法。
RPC框架的出现让调用者不必关心底层细节,处理了数据序列化、反序列化、连接管理、收发线程、超时处理等问题,是一种优秀的微服务架构。

gRPC如何在HTTP2上传输

gRPC请求&响应流程

gRPC在HTTP2的基础上定义了request和response的规范。
以下是gRPC请求&响应消息流中消息原子的一般顺序:

gRPC的请求报头直接使用HTTP2头部,在HEADERS+CONTINUATION帧中传递。
举例说明:单独调用HTTP2帧序列

HEADERS (flags = END_HEADERS)
:method = POST
:scheme = http
:path = /google.pubsub.v2.PublisherService/CreateTopic
:authority = pubsub.googleapis.com
grpc-timeout = 1S
content-type = application/grpc+proto
grpc-encoding = gzip
authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v

DATA (flags = END_STREAM)
<Length-Prefixed Message>
HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip
content-type = application/grpc+proto

DATA
<Length-Prefixed Message>

HEADERS (flags = END_STREAM, END_HEADERS)
grpc-status = 0 # OK
trace-proto-bin = jher831yy13JHy3hc

HTTP2传输映射

gRPC 的 service 接口是基于 protobuf 定义的,我们可以非常方便的将 service 与 HTTP/2 关联起来,在HTTP2之上带来额外的优势。格式如下:

Path : /Service-Name/{method name}  
Service-Name : ?( {proto package name} "." ) {service name}  
Message-Type : {fully qualified proto message name}  
Content-Type : "application/grpc+proto"  

HTTP2的这些优点为gRPC的高性能提供了保障,而gRPC也为通过HTTP2进行流传输提供了广泛的支持(无串流、服务器到客户端流、客户端到服务器流、双向流),在延迟和网络吞吐量方面的表现都很优秀(特别是比起传统的REST+HTTP1),更适用于分布式部署。这些特性使得gRPC在移动设备上表现尤为出色,更省电、节省空间占用。
当然,gRPC也有其劣势:由于gRPC大量使用HTTP2功能,没有浏览器能提供Web请求所需的控制级别来支持gRPC客户端,比如不允许调用者使用HTTP的要求,或提供对基础HTTP帧的访问(Chrome会崩溃的)。gRPC-Web是gRPC团队的另一项技术,可以在浏览器中提供优先的gRPC。gRPC-Web由两部分组成,一个支持所有现代浏览器的JavaScript客户端,以及服务器上的一个gRPC-Web代理。gRPC-Web客户端调用代理,代理将根据gRPC请求转发到gRPC服务器。gRPC-Web并非支持所有gRPC的功能。不支持客户端和双向流,并且对服务器流的支持有限。
由于gRPC消息使用Protobuf编码。尽管Protobuf可以高效地发送和接收,但其二进制格式不是人类可读的。Protobuf要求在.proto文件中指定的消息接口描述才能正确反序列化。需要额外的工具来分析网上的Protobuf有效载荷并手动撰写请求。为了解决这个问题,存在诸如服务器反射和gRPC命令行工具之类的功能来辅助二进制Protobuf消息。此外,protobuf消息支持与JSON之间的转换。内置的JSON转换提供了一种在调试时将Protobuf消息与人类可读格式之间相互转换的有效方法。

gRPC相关项目

gRPC该存储库包含在共享C核心库src / core之上编写的以多种语言实现的gRPC库的源代码,并欢迎对其代码库做出贡献。 在大多数语言中,gRPC运行时是作为软件包提供的。不同语言的gRPC库处于发展状态,正在寻求贡献:

Language Source Repo
Java grpc-java
Go grpc-go
Language Source
Shared C [core library] src/core
C++ src/cpp
Ruby src/ruby
Python src/python
PHP src/php
C#(core library based) src/csharp

ref

谁能用通俗的语言解释一下什么是 RPC 框架?
RPC简介及框架选择
gRPC学习笔记
grpc.io
gRPC over HTTP2
无所不能的RPC消息协议是如何设计的?
深入了解 gRPC:协议
Is gRPC(HTTP/2) faster than REST with HTTP/2?
开源中国翻译:gRPC官方文档中文版
Compare gRPC services with HTTP APIs