前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >gRPC & Protocol Buffers

gRPC & Protocol Buffers

作者头像
Helloted
发布2022-06-08 10:24:57
7430
发布2022-06-08 10:24:57
举报
文章被收录于专栏:Helloted
0、gRPC

gRPC 是一个高性能、开源、通用的RPC框架,由Google推出,基于HTTP/2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务,并且为客户端和服务端自动生成可靠的功能库。

gRPC 提供 protocol buffer 编译插件,能够从一个服务定义的 .proto 文件生成客户端和服务端代码。通常 gRPC 用户可以在服务端实现这些API,并从客户端调用它们。

  • 在服务侧,服务端实现服务接口,运行一个 gRPC 服务器来处理客户端调用。gRPC 底层架构会解码传入的请求,执行服务方法,编码服务应答。
  • 在客户侧,客户端有一个存根实现了服务端同样的方法。客户端可以在本地存根调用这些方法,用合适的 protocol buffer 消息类型封装这些参数— gRPC 来负责发送请求给服务端并返回服务端 protocol buffer 响应。

gRPC 允许你定义四类服务方法:

  • 单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。
  • 服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。
  • 客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。
  • 双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。
1、Protocol Buffers

Google Protocol Buffer( 简称 Protobuf) ,Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

Protobuf实际是一套类似Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。通信时所传递的信息是通过Protobuf定义的message数据结构进行打包,然后编译成二进制的码流再进行传输或者存储。

相比较而言,Protobuf有如下优点:

  • 序列化后体积很小:消息大小只需要XML的1/10 ~ 1/3
  • 解析速度快:解析速度比XML快20 ~ 100倍
  • 多语言支持
  • 更好的兼容性,Protobuf设计的一个原则就是要能够很好的支持向下或向上兼容
2、Protocol Buffers特点
代码语言:javascript
复制
message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  • 序列化数据时,不序列化key的name,使用key的编号替代,减小数据。如上面的数据在序列化时query ,page_number以及result_per_page的key不会参与,由编号1,2,3替代,这样在反序列的时候可以直接通过编号找到对应的key,这样做确实可以减小传输数据,但是编号一旦确定就不可更改;
  • 版本直接兼容:字段操作可以在无需重新部署程序的情况下更新数据结构
    • 必须不可以改变已经存在的标签的数字
    • 必须不可以增加或删除必须(required)字段。
    • 可以删除可选(optional)或重复(repeated)字段。
    • 可以添加新的可选或重复字段,但是必须使用新的标签数字,必须是之前的字段所没有用过的。
  • 没有赋值的key,不参与序列化:序列化时只会对赋值的key进行序列化,没有赋值的不参与,在反序列化的时候直接给默认值即可;
  • 可变长度编码:主要缩减整数占用字节实现,例如java中int占用4个字节,但是大多数情况下,我们使用的数字都比较小,使用1个字节就够了,这就是可变长度编码完成的事;
  • TLV: TLV全称为Tag_Length_Value,其中Tag表示后面数据的类型,Length不一定有,根据Tag的值确定,Value就是数据了,TLV表示数据时,减少分隔符的使用,更加紧凑;
3、数据结构

Tag块并不是只表示数据类型,其中数据编号也在Tag块中,Tag的生成规则如下:Tag块的后3位表示数据类型,其他位表示数据编号。Tag中1-15编号只占用1个字节,所以确保编号中1-15为常用的,减少数据大小。

其中Length不一定有,依据Tag确定,例如数值类型的数据,使用VarInts不需要长度,就只有Tag-Value,string类型的数据就必须是Tag-Length-Value

4、数据类型

类型

释义

备注

0

可变长度编码

int32 int64 uint32 uint64 sint32 sint64 bool enum

1

64位固定长度

fixed64 sfixed64 double

2

value 的长度

string bytes message packed repeated fiels

3

Start Group

已废弃

4

End Group

已废弃

5

32位长度

fixed32 sfixed32 float

代码语言:javascript
复制
(field_number << 3) | wire_type

低三位表示wire type,其他的位表示field number(编号)。

5、VARInts/Zigzag

int值一般都是固定的4字节,可表示的整数范围为-2^31——2^31-1,但是实际开发中用到的数字均比较小,会造成字节浪费。

Varints是protobuf的序列化整型数据的一种编码方式,它的优点是整型数据的值越小,编码后所用的字节数越小。

经过Varints编码后的数据,它的每一个字节8bit的高位代表一个标记位。

  • 如果标记位是1,则代表下一个字节仍然是当前整型数据的组成;
  • 如果标记位是0,则代表下一个字节就是下一个整型数据了。

先看最简单的数值1,一个字节足以表示它,所以它的标记位置0:

代码语言:javascript
复制
0000 0001

再看数值300,经过Varints编码后的序列:

代码语言:javascript
复制
1010 1100 0000 0010

换算的时候,从左到右,依次将每个字节的高位(标志位)去掉,Protocol Buffer是低位在前,转换后拼接

代码语言:javascript
复制
	1010 1100 0000 0010
	(去除标志位)
→  010 1100  000 0010
  (转换拼接)
→  000 0010  010 1100
	(进制)
→	 300

可变长度编码唯一的缺点就是当数很大的时候int32需要占用5个字节,但是从统计学角度来说,一般不会有这么大的数。

对于负数的处理方式是不同的。如果用int32或者int64来编码一个负数的话,通常需要耗费10个字节来表示,因为负数在计算机中是以补码表示的,相当于一个数值很大的无符号数。

所以这个时候就需要用「有符号」的整型(sint32,sint64)来表示负数了,它们先使用ZigZag编码方式将负数转换为绝对值较小正数,再进行Varints编码。

6、编码
代码语言:javascript
复制
message Test1{    
		required int32 id = 1;
}

如果我们将number赋值为300,则Message进行编码序列化以后以16进制输出为

代码语言:javascript
复制
08 96 01

其中第一个字节08

代码语言:javascript
复制
0000 1000

wire type为0,field name为1。符合id的类型是int32,编码方式是Varints,field是1的这一情况。

12c 02则分别为1010 1100和0000 0010的16进制

代码语言:javascript
复制
message Test2
{
    required string str = 2;
}

如果将str赋值为’testing’,然后把经过protobuf编码序列化后的数据以16进制的方式输出

代码语言:javascript
复制
12 07 74 65 73 74 69 6e 67

第一个字节0x12表示field name为2,wire type为2。第二个字节0x07表示数据长度为7,所以后面7个字节就是使用UTF8编码的testing。

7、总结
  1. Protocol Buffer 利用 varint 原理压缩数据以后,二进制数据非常紧凑,option 也算是压缩体积的一个举措。所以 pb 体积更小,如果选用它作为网络数据传输,势必相同数据,消耗的网络流量更少。但是并没有压缩到极限,float、double 浮点型都没有压缩。
  2. Protocol Buffer 比 JSON 和 XML 少了 {、}、: 这些符号,体积也减少一些。再加上 varint 压缩,gzip 压缩以后体积更小!
  3. Protocol Buffer 是 Tag - Value (Tag - Length - Value)的编码方式的实现,减少了分隔符的使用,数据存储更加紧凑。
  4. Protocol Buffer 另外一个核心价值在于提供了一套工具,一个编译工具,自动化生成 get/set 代码。简化了多语言交互的复杂度,使得编码解码工作有了生产力。
  5. Protocol Buffer 不是自我描述的,离开了数据描述 .proto 文件,就无法理解二进制数据流。这点即是优点,使数据具有一定的“加密性”,也是缺点,数据可读性极差。所以 Protocol Buffer 非常适合内部服务之间 RPC 调用和传递数据。
  6. Protocol Buffer 具有向后兼容的特性,更新数据结构以后,老版本依旧可以兼容,这也是 Protocol Buffer 诞生之初被寄予解决的问题。因为编译器对不识别的新增字段会跳过不处理。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0、gRPC
  • 1、Protocol Buffers
  • 2、Protocol Buffers特点
  • 3、数据结构
  • 4、数据类型
  • 5、VARInts/Zigzag
  • 6、编码
  • 7、总结
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档