【转载】gRPC学习笔记

原文连接: https://zhuanlan.zhihu.com/p/...

rpc框架概述

微服务架构是近期比较流行的架构,知乎也实现了服务化。要实现服务化,则首先要解决各个服务之间的通讯问题。那么就会面临数据序列化、反序列化、链接管理、收发线程、超时处理等问题。若是本身实现一套这样的机制,不但重复劳动,性能和效率也难以保证。rpc框架的出现解决了这些问题,让调用者没必要关心底层细节。目前主流的rpc框架有Apache Thrift、gRPC、Netty等。Apache Thrift和gRPC都是跨语言的rpc框架,他们采用了IDL来描述数据类型和接口,使用编译器编译出特定语言的代码从而实现跨语言的rpc。本文主要介绍gRPC的规范及实现。html

gRPC实现

rpc框架通常基于tcp或者http协议实现。基于http的rpc框架有许多优势,HTTP/1.x协议简单明了,是目前最流行的应用层协议,有着很是成熟且完善的各类基础设施,如负载均衡、监控、代理等,适用性普遍,各个设备系统均有实现。可是缺点也很明显,就是HTTP/1.x采用的是文本协议,解析速度慢,带宽占用高。并且request/response的通讯方法致使总体效率不高。gRPC基于HTTP2协议,HTTP2 使得grpc 可以更好的适用于移动客户端和服务端通讯的使用场景,而且链接多路复用也保证了RPC 的效率。grpc 的协议设计上很好的使用了HTTP2 现有的语义,请求和响应的数据使用HTTP Body 发送,其余的控制信息则用Header 表示。nginx

HTTP2基本概念git

流(Stream)github

流是服务器和客户端在HTTP/2链接内用于交换帧数据的独立双向序列,逻辑上可看作一个较为完整的交互处理单元,即表达一次完整的资源请求-响应数据交换流程;一个业务处理单元,在一个流内进行处理完毕,这个流生命周期完结。web

特色以下:算法

  • 一个HTTP/2链接可同时保持多个打开的流,任一端点交换帧
  • 客户端、服务端双方均可以创建流,流也能够被任意一方关闭
  • 流的标识符天然数表示,1~2^31-1区间,有建立流的终端分配
  • 客户端发起的流使用奇数流ID,服务端发起的使用偶数,ID为0、1的流保留
  • HTTP/2链接上传输的每一个帧都关联到一个流,一个链接上能够同时有多个流
  • 同一个流的帧按序传输,不一样流的帧交错混合传输

帧(Frame)chrome

HTTP/2抛弃HTTP/1的文本协议改成二进制协议,HTTP2的基本传输单元为帧,每一个帧都从属于某个流。json

帧的格式以下:api

  • - Length: Payload 长度
  • - Type: 帧类型
  • - Stream identifier:所属流ID
  • - Frame Payload: 依帧类型而不一样

帧的类型有:浏览器

  • - HEADERS 对应HTTP/1的 Headers
  • - DATA 对应HTTP/1的 Body
  • - CONTINUATION 头部太大,分多个帧传输(一个HEADERS+若干CONTINUATION)
  • - SETTINGS 链接设置
  • - WINDOW_UPDATE 流量控制
  • - PUSH_PROMISE 服务端推送
  • - PRIORITY 流优先级更改
  • - PING 心跳或计算RTT
  • - RST_STREAM 立刻停止一个流
  • - GOAWAY 关闭链接而且发送错误信息

流是为了实现多路复而提出的逻辑概念,在一个链接上能够同时存在多个流。而流是由一个个的帧组成,在一个流里面的帧是有序的,多个流之间的帧能够混杂在一块儿传输。

gRPC over HTTP2

gRPC在HTTP2的基础上定义了request和response的规范。使用header帧描述meta信息如超时时间、payload的压缩算法等等。使用data帧传输具体的rpc参数和返回结果。

request header

scheme: http或者https

method: 固定为POST

path: 服务名/rpc方法名

content-type: 目前取值都是application/grpc+proto,或json或其余自定义协议

grpc-encoding 能够有gzip, deflate, snappy 等取值,表示采用的压缩方法。

grpc-timeout 表示调用的超时时间,单位有Hour(H), Minute(M), Second(S), Millisecond(m), Microsecond(u), Nanosecond(n) 等。

response header

response有两种,通常状况下response都要包含有header帧、数据帧和trailer。若是服务端发生了错误,则能够只返回一个trailer即 Trailers-Only 。

Response-Headers 主要包括 HTTP-Status,Content-Type 以及 Custom-Metadata 等。Trailers-Only 也有 HTTP-Status ,Content-Type 和 Trailers。Trailers 包括了 Status 以及 0 或者多个 Custom-Metadata。

HTTP-Status 就是咱们一般的 HTTP 200,301,400 这些,很通用就再也不解释。Status 也就是 gRPC 的 status, 而 Status-Message 则是 gRPC 的 message。Status-Message 采用了 Percent-Encoded 的编码方式,具体参考这里

若是在最后收到的 HEADERS frame 里面,带上了 Trailers,而且有 END_STREAM 这个 flag,那么就意味着 response 的 EOS。

Request例子:

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)
<Delimited Message>

Response例子:

HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip

DATA
<Delimited Message>

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

从图中能够看出,客户端的每次rpc调用都发起了一个流,而后在这个流中发送header帧和数据帧,而服务端的返回结过结果也是使用同一个流进行传输。

虽然说gRPC使用HTTP/2协议,不少浏览器也开始支持HTTP2,可是目前还不能使用浏览器做为客户端访问gRPC服务。由于gRPC的response在数据帧以后还有一个trailer header帧(这个帧内包含了grpc-status和grpc-message头),这会致使chrome的崩溃。为了解决这一问题一个新项目grpc-web正在开发之中,还处于early access阶段,参见这里。grpc-web在grpc over HTTP2的基础上修改和新增了一些规范,使得可以经过浏览器和JavaScript调用gRPC服务,参见这里

Nginx目前也没法代理gRPC服务。虽然nginx从1.9.5版本开始支持HTTP2,可是还不支持反向代理HTTP2的upstreaming。参见这里

目前可行的经过浏览器访问grpc的方法是使用一个gateway,在grpc服务和浏览器之间做为中介,接受浏览器的Restful请求转换成grpc标准的请求发送到服务端。参见这个项目

相关文章
相关标签/搜索