gRPC学习笔记(三)——底层原理

protocol buffers

报文结构

protocol buffers编码格式是尽量将字段的元信息和字段的值进行压缩存储,其中字段的元信息中包含对这个字段描述的所有信息。

protocol buffers 序列化后的报文结构如下图所示,整个报文是一个二进制流,其中字段按照定义的顺序紧紧相邻,每个字段包含一个字段标识符(tag)和字段的值(value)。

protobuf.jpg

标签部分由两个值构成:

  • 字段索引:字段索引是在proto文件中定义消息时,为每个消息字段所设置的唯一数字。
  • 线路类型(wire type):线路类型基于字段类型,它可以提供信息来确定值的长度。

线路类型和字段类型的映射如下表所示。

线路类型 分类 说明 字段类型
0 VARINT 要用variant编码对所传入的数据做压缩存储 int32,int64,uint32,uint64,sint32,sint64,bool,enum
1 FIXED64 固定64位长度,不压缩 fixed64,sfixed64,double
2 LENGTH_DELIMITED 针对需要存储长度的类型 string,bytes,嵌入式消息, 打包的 repeadted 字段
3 START_GROUP 一个组(该组可以是嵌套类型,也可以是repeated类型)的开始标志 groups(已废弃)
4 END_GROUP 一个组(该组可以是嵌套类型,也可以是repeated类型)的结束标志 groups(已废弃)
5 FIXED32 固定32位长度,不压缩 fixed32,sfixed32,float

线路类型在报文中占3位,因此可以用下面的公式确定标签的值。

tag_value = (field_index << 3) | wire_type

编码技术

protocol buffers 将支持的字段类型分成不同的组(参考线路类型),每组使用不同的技术来编码。

Varint

Varint(可变长度整数)是使用单字节或者多字节来序列化整数的方法。它基于的思想是:整数的值并不均匀分布,每个值所占的字节数量并不固定,而依赖具体的值。

在 Varint 中,除了最后的字节,其它所有字节都会设置最高有效位(most significant bit,MSB)表明后面还有字节。每字节中较低的7位用来存储数字的二进制补码形式,同时最低有效位放在前面。

对于有符号整数sint32和sint64,会首先使用zigzag编码来将有符号整数转换成无符号整数再使用Varint编码。

zigzag编码中有符号整数会将正整数和负整数以“之”字形方式映射位无符号整数,如下表。

原始有符号整数 映射的无符号整数
0 0
-1 1
1 2
-2 3
-2 4

因此,对于负整数,更推荐sint32和sint64而不是int32和int64。因为后者会将负值直接转换成二进制值,比前者占用更多的字节。

FIXED64 和 FIXED32

这两种会被分配固定的字节,字节数和实际值没有关系。

字符串类型

由前文可知,字符串类型属于基于长度分隔(length-delimited)的线路类型。这意味着说先会有一个经过 Varint 编码的长度值,随后才是指定数量的字节数据。字符串值会使用UTF-8字符编码格式来进行编码。

基于长度前缀的消息分帧

消息分帧(message-framing)是通信中一种常用技术,主要用来保证数据传输准确性以及处理数据过长场景。gRPC 中使用了长度前缀分帧(length-prefix framing)的消息分帧技术。

长度前缀分帧是指再写入消息之前先写入长度信息。在 gRPC 中每条消息使用4字节来设置其大小,这意味着 gRPC 可以处理的消息最大不超过 4GB。

如下图所示,消息使用大端(big-endian)格式表示内容大小,另外帧中还有一维的压缩标志,表明消息是否使用了压缩。

grpc1.jpg

基于 HTTP/2 通信的 gRPC

gRPC 基于 HTTP/2 通信,本部分介绍 gRPC 和 HTTP/2 的关系。

HTTP/2

首先介绍一下 HTTP/2 ,HTTP/2 支持 HTTP/1.1 的所有核心特性,只不过实现方式更加高效,下面会介绍 HTTP/2 中的几个基本概念。

流(Stream)

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

它的特点如下:

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

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

帧(frame)

HTTP/2抛弃HTTP/1的文本协议改为二进制协议,HTTP2的基本传输单元为帧,每个帧都从属于某个流。帧中标记着这个帧所属的流。

消息(message)

消息是指完整的帧序列,映射为一条逻辑上的HTTP消息,由一帧或多帧组成。客户端和服务端可以将消息分解成独立的帧并交叉发送,然后在另一端重新组合。

HTTP/2中的 gRPC

gRPC 在 HTTP/2 的基础上定义了请求消息(request)和返回消息(response)的规范。使用 header 帧描述元数据信息如超时时间、payload的压缩算法等等。使用 data 帧传输具体的参数和返回结果。

请求消息

请求信息主要包含3部分:请求头、带长度前缀的消息和流结束标记(end of stream)

请求头信息格式如下:

HEADERS (flags = END_HEADERS)
:method = POST // HTTP方法,gRPC中固定为POST
:scheme = http // HTTP模式,如果允许TLS,则使用 https,否则为http
:path = /xxx/xxx // 端点的路径:/{service name}/{method name}
:authority = abc.com // 定义目标 URI 的虚拟主机名
te = trailers // 定义不兼容代理的检测,gRPC 中必须是 trailers
grpc-timeout = 1S // 定义超时时间,如果不定义,则默认为无穷大
content-type = application/grpc // 定义content-type,gRPC 必须以 application/grpc 为前缀,否则的话,gRPC 服务器会返回一个 415 响应码
grpc-encoding = gzip // 定义消息压缩类型
authorization = Bearer xxxxxx</pre> // 可选元数据,authorization用来访问安全的端点

其中包含一些需要注意的点:

  • 以冒号 : 开头的字段称为保留头,即 HTTP/1.1 中包含的报文头字段,HTTP/2 要求保留头必须写在其他头部字段之前。

  • gRPC 的头部字段可以分为两类:调用定义的报文头(call-definition headers)和自定义元数据(custom metadata)。

    • 调用定义的报文头是由 HTTP/2 预定义的报文头,必须设置在自定义元数据之前。

    • 自定义元数据由应用层定义的任意键值对,注意自定义时不要使用grpc-开头的键名,这些是保留的键名。

请求消息通过在最后一个DATA帧上加上 END_STREAM 标志来结束。

    DATA (flags = END_STREAM)
    <Length-Prefixed Message></pre>

响应消息

响应消息同样包含3部分:响应头、带长度前缀的消息和trailer,其中消息部分不是必须的。

响应头格式如下:

    HEADERS (flags = END_HEADERS)
    :status = 200
    grpc-encoding = gzip
    content-type = application/grpc</pre>

发送完响应头后,如果包含消息,就会按数据帧发送带长度前缀的消息。END_STREAM 标记不会和数据帧一起发送,而是作为单独的头信息发送,名为trailer。

    HEADERS (flags = END_STREAM, END_HEADERS)
    grpc-status = 0 // 返回状态码
    grpc-message = xxxxxx</pre> // 对返回错误的描述信息,可选

如果调用请求直接失败,返回不包含数据帧,服务端只发送 trailer,它会以 HTTP/2 报文头帧的形式返回,并包含 END_STREAM 标记。

gRPC 通信模式中的消息流

前文已经讲过 gRPC通信的 4 种模式:一元 RPC 模式、服务端流 RPC 模式、客户端流 RPC 模式以及双向流 RPC 模式。本部分结合本文内容讲述每种模式的运行方式。

一元 RPC 模式

一元 RPC 模式中,gRPC 服务端和客户端之间通信只涉及一个请求和一个响应,其中以长度为前缀的消息中可以包含一个或多个数据帧。

simple-grpc.jpg

服务端流 RPC 模式

请求信息流和 一元 RPC 模式相同,区别是服务端不再向客户端发送一条响应消息,而是多条响应消息流。服务端持续等待到接收到完整请求消息后,就会发送响应头消息和多条以长度为前缀的消息,最后发送 trailer 头信息后通信关闭。

server-streaming-grpc.jpg

客户端流 RPC 模式

在客户端流 RPC 模式中,客户端向服务器发送多条消息,即先发送头信息建立连接,然后发送多条带长度前缀的消息,最后在末尾的数据帧会发送 EOS 标记,接下来会将连接设置为半关(只接收不发送)状态。服务端在接收到客户端的所有消息后发送一条响应消息。

client-streaming-grpc.jpg

双向流 RPC 模式

双向流 RPC 模式中,客户端发送头信息帧与服务端建立连接,然后它们互发带长度前缀的消息,无需等待对方结束。发送完消息后关闭己方一侧的连接。

bidirectional-streaming-grpc.jpg

gRPC 实现架构

gRPC 实现架构如下所示。

grpc-architecture.jpg

在通信层之上的 gRPC 核心层用来抽象网络操作,并对认证等核心功能进行扩展。

代码生成API在应用层,主要处理应用程序逻辑和数据编码逻辑,各个语言会提供不同的API。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容

  • gRPC 主要使用同步请求-响应模型来交互,但是在初次连接建立后,可以实现全异步或者流模式; SOAP:Simpl...
    苏慕漓阅读 1,219评论 0 0
  • 通过三篇笔记简单介绍下 gRPC,后续进行代码实践。 gRPC 介绍 gRPC 是一个高性能、跨平台、开源和通用的...
    简单一点点阅读 325评论 0 0
  • 0. 背景 gRPC 是谷歌开源的轻量级 RPC 通信框架,在微服务架构中经常用到。 1. gRPC 简介 gR...
    张云飞Vir阅读 702评论 0 0
  •  gRPC 学习笔记,记录gprc一些基本概念.  gRPC正如其他 RPC 系统,gRPC 基于如下思想:定义一...
    Jancd阅读 1,982评论 1 7
  • 本文为学习记录,如有侵权,请联系删除 为何需要使用Thrift协议? 首先,Thrift是基于socket的,通过...
    wxxhfg阅读 960评论 1 1