gRPC

简介

  • gRPC是由Google公司开源的高性能RPC框架。

  • gRPC支持多语言

    gRPC原生使用C、Java、Go进行了三种实现,而C语言实现的版本进行封装后又支持C++、C#、Node、ObjC、 Python、Ruby、PHP等开发语言

  • gRPC支持多平台

    支持的平台包括:Linux、Android、iOS、MacOS、Windows

  • gRPC的消息协议使用Google自家开源的Protocol Buffers协议机制(proto3) 序列化

  • gRPC的传输使用HTTP/2标准,支持双向流和连接多路复用

架构

C语言实现的gRPC支持多语言,其架构如下

使用方法

安装

pip install grpc 
pip install grpcio-tools 

使用

  1. 使用Protocol Buffers(proto3)的IDL接口定义语言定义接口服务,编写在文本文件(以.proto为后缀名)中。
  2. 使用protobuf编译器生成服务器和客户端使用的stub代码
  3. 编写补充服务器和客户端逻辑代码
 

Protocol Buffers

Protocol Buffers 是一种与语言无关,平台无关的可扩展机制,用于序列化结构化数据。使用Protocol Buffers 可以一次定义结构化的数据,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。

现在有许多框架等在使用Protocol Buffers。gRPC也是基于Protocol Buffers。 Protocol Buffers 目前有2和3两个版本号。

在gRPC中推荐使用proto3版本。

1 文档结构

1) Protocol Buffers版本

Protocol Buffers文档的第一行非注释行,为版本申明,不填写的话默认为版本2。

syntax = "proto3"; 或者 syntax = "proto2"; 

2)Package包

Protocol Buffers 可以声明package,来防止命名冲突。 Packages是可选的。

package foo.bar; message Open { ... } 

使用的时候,也要加上命名空间,

message Foo {   ...   foo.bar.Open open = 1;   ... } 

注意:对于Python而言,package会被忽略处理,因为Python中的包是以文件目录来定义的。

3)导入

Protocol Buffers 中可以导入其它文件消息等,与Python的import类似。

import “myproject/other_protos.proto”; 

4)定义各种消息和服务

消息messge是用来定义数据的,服务service是用来gRPC的方法的。

2 注释

Protocol Buffers 提供以下两种注释方式。

// 单行注释 /*  多行注释  多行注释  */ 

3 数据类型

3.1 基本数据类型

.proto 说明 Python
double   float
float   float
int32 使用变长编码,对负数编码效率低, 如果你的变量可能是负数,可以使用sint32 int
int64 使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint64 int/long
uint32 使用变长编码 int/long
uint64 使用变长编码 int/long
sint32 使用变长编码,带符号的int类型,对负数编码比int32高效 int
sint64 使用变长编码,带符号的int类型,对负数编码比int64高效 int/long
fixed32 4字节编码, 如果变量经常大于2^{28} 的话,会比uint32高效 int
fixed64 8字节编码, 如果变量经常大于2^{56} 的话,会比uint64高效 int/long
sfixed32 4字节编码 int
sfixed64 8字节编码 int/long
bool   bool
string 必须包含utf-8编码或者7-bit ASCII text str
bytes 任意的字节序列 str

3.2 枚举

在 Proto Buffers 中,我们可以定义枚举和枚举类型,

enum Corpus {     UNIVERSAL = 0;     WEB = 1;     IMAGES = 2;     LOCAL = 3;     NEWS = 4;     PRODUCTS = 5;     VIDEO = 6; } Corpus corpus = 4; 

枚举定义在一个消息内部或消息外部都是可以的,如果枚举是 定义在 message 内部,而其他 message 又想使用,那么可以通过 MessageType.EnumType 的方式引用。

定义枚举的时候,我们要保证第一个枚举值必须是0,枚举值不能重复,除非使用 option allow_alias = true 选项来开启别名。

enum EnumAllowingAlias {     option allow_alias = true;     UNKNOWN = 0;     STARTED = 1;     RUNNING = 1; } 

枚举值的范围是32-bit integer,但因为枚举值使用变长编码,所以不推荐使用负数作为枚举值,因为这会带来效率问题。

4 消息类型

Protocol Buffers使用message定义消息数据。在Protocol Buffers中使用的数据都是通过message消息数据封装基本类型数据或其他消息数据,对应Python中的类。

message SearchRequest {   string query = 1;   int32 page_number = 2;   int32 result_per_page = 3; } 

4.1 字段编号

消息定义中的每个字段都有唯一的编号。这些字段编号用于以消息二进制格式标识字段,并且在使用消息类型后不应更改。 请注意,1到15范围内的字段编号需要一个字节进行编码,包括字段编号和字段类型。16到2047范围内的字段编号占用两个字节。因此,您应该为非常频繁出现的消息元素保留数字1到15。请记住为将来可能添加的常用元素留出一些空间。

最小的标识号可以从1开始,最大到2^29 - 1,或 536,870,911。不可以使用其中的[19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。如果非要在.proto文件中使用这些预留标识号,编译时就会报警。同样你也不能使用早期保留的标识号。

4.2 指定字段规则

消息字段可以是以下之一:

  • singular:格式良好的消息可以包含该字段中的零个或一个(但不超过一个)。

  • repeated:此字段可以在格式良好的消息中重复任意次数(包括零)。将保留重复值的顺序。对应Python的列表。

      message Result {     string url = 1;     string title = 2;     repeated string snippets = 3;   } 

4.3 添加更多消息类型

可以在单个.proto文件中定义多个消息类型。

message SearchRequest {   string query = 1;   int32 page_number = 2;   int32 result_per_page = 3; }  message SearchResponse {  ... } 

4.4 保留字段

保留变量不被使用

如果通过完全删除字段或将其注释来更新消息类型,则未来用户可以在对类型进行自己的更新时重用字段编号。如果以后加载相同的旧版本,这可能会导致严重问题,包括数据损坏,隐私错误等。确保不会发生这种情况的一种方法是指定已删除字段的字段编号(或名称)reserved。如果将来的任何用户尝试使用这些字段标识符,protobuf编译器将会报错。

message Foo {   reserved 2, 15, 9 to 11;   reserved "foo", "bar"; } 

4.5 默认值

解析消息时,如果编码消息不包含特定的单数元素,则解析对象中的相应字段将设置为该字段的默认值。这些默认值是特定于类型的:

  • 对于字符串,默认值为空字符串。
  • 对于字节,默认值为空字节。
  • 对于bools,默认值为false。
  • 对于数字类型,默认值为零。
  • 对于枚举,默认值是第一个定义的枚举值,该值必须为0。
  • 对于消息字段,未设置该字段。它的确切值取决于语言。
  • 重复字段的默认值为空(通常是相应语言的空列表)。

4.6 嵌套类型

你可以在其他消息类型中定义、使用消息类型,在下面的例子中,Result消息就定义在SearchResponse消息内,如:

message SearchResponse {   message Result {     string url = 1;     string title = 2;     repeated string snippets = 3;   }   repeated Result results = 1; } 

如果要在其父消息类型之外重用此消息类型,使用

SearchResponse.Result 

5 map映射

如果要在数据定义中创建关联映射,Protocol Buffers提供了一种方便的语法:

map< key_type, value_type> map_field = N ; 

其中key_type可以是任何整数或字符串类型。请注意,枚举不是有效的key_type。value_type可以是除map映射类型外的任何类型。

例如,如果要创建项目映射,其中每条Project消息都与字符串键相关联,则可以像下面这样定义它:

map<string, Project> projects = 3 ; 
  • map的字段可以是repeated。
  • 序列化后的顺序和map迭代器的顺序是不确定的,所以你不要期望以固定顺序处理map
  • 当为.proto文件产生生成文本格式的时候,map会按照key 的顺序排序,数值化的key会按照数值排序。
  • 从序列化中解析或者融合时,如果有重复的key则后一个key不会被使用,当从文本格式中解析map时,如果存在重复的key,则解析可能会失败。
  • 如果为映射字段提供键但没有值,则字段序列化时的行为取决于语言。在Python中,使用类型的默认值。

6 oneof

如果你的消息中有很多可选字段, 并且同时至多一个字段会被设置, 你可以加强这个行为,使用oneof特性节省内存。

为了在.proto定义oneof字段, 你需要在名字前面加上oneof关键字, 比如下面例子的test_oneof:

message SampleMessage {   oneof test_oneof {     string name = 4;     SubMessage sub_message = 9;   } } 

然后你可以增加oneof字段到 oneof 定义中. 你可以增加任意类型的字段, 但是不能使用repeated 关键字。

7 定义服务

Protocol Buffers使用service定义RPC服务。

示例:

message HelloRequest {   string greeting = 1; }  message HelloResponse {   string reply = 1; }  service HelloService {   rpc SayHello (HelloRequest) returns (HelloResponse) {} }

syntax = "proto3";

message UserRequest {
string user_id=1;
int32 channel_id=2;
int32 article_num=3;
int64 time_stamp=4;
} message Track {
string click=1;
string collect=2;
string share=3;
string read=4;
} message Article {
int64 article_id=1;
Track track=2;
} message ArticleResponse {
string exposure=1;
int64 time_stamp=2;
repeated Article recommends=3;
} service UserRecommend {
rpc user_recommend(UserRequest) returns(ArticleResponse) {}
}

  


代码生成

编译生成代码

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. reco.proto
  • -I表示搜索proto文件中被导入文件的目录
  • --python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的数据类型
  • --grpc_python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的服务类型

在toutiao-backend/common/rpc目录下执行上述命令,会自动生成如下两个rpc调用辅助代码模块:

  • reco_pb2.py 保存根据接口定义文件中的数据类型生成的python类
  • reco_pb2_grpc.py 保存根据接口定义文件中的服务方法类型生成的python调用RPC方法

gRPC【RPC自定义http2.0协议传输】的更多相关文章

  1. 【HTTP】402- 深入理解http2.0协议,看这篇就够了!

    本文字数:3825字 预计阅读时间:20分钟 导读 http2.0是一种安全高效的下一代http传输协议.安全是因为http2.0建立在https协议的基础上,高效是因为它是通过二进制分帧来进行数据传 ...

  2. HTTP2.0协议

    HTTP2.0协议 http2协议的草案已经出来了,阅读了一下网上的中文版,http2尽可能的兼容http1.1.改进了http1.1协议的不足. http1.0和http1.1的缺点: 1.http ...

  3. nginx安装http2.0协议

    1.HTTP2协议 HTTP 2.0 的主要目标是改进传输性能,实现低延迟和高吞吐量.从另一方面看,HTTP 的高层协议语义并不会因为这次版本升级而受影响.所有HTTP 首部.值,以及它们的使用场景都 ...

  4. HTTP2.0那些事

    1. HTTP2.0的前世 http2.0的前世是http1.0和http1.1这两兄弟.虽然之前仅仅只有两个版本,但这两个版本所包含的协议规范之庞大,足以让任何一个有经验的工程师为之头疼.http1 ...

  5. http2.0与http1.X的区别

    此文只是方便重看,原文在:http://www.mamicode.com/info-detail-1199706.html 1.1 HTTP应用场景 http诞生之初主要是应用于web端内容获取,那时 ...

  6. HTTP2.0 简明笔记

    前言 RFC2616发布以来,一直是互联网发展的基石.HTTP协议也成为了可以在任何领域使用的核心协议,基于这个协议人们设计和部署了越来越多的应用.HTTP的简单本质是其快速发展的关键,但随着越来越多 ...

  7. 杂谈:HTTP1.1 与 HTTP2.0 知多少?

    HTTP是应用层协议,是基于TCP底层协议而来. TCP的机制限定,每建立一个连接需要3次握手,断开连接则需要4次挥手. HTTP协议采用"请求-应答"模式,HTTP1.0下,HT ...

  8. HTTP2.0简明笔记

    版权声明:本文由史燕飞原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/82 来源:腾云阁https://www.qcloud ...

  9. http1.1与http2.0

    简介 http1.0: 1.0版本中每个TCP连接只能发送一个请求,数据发送完毕连接就关闭,如果还要请求其他资源,就必须重新建立TCP连接.(TCP为了保证正确性和可靠性需要客户端和服务器三次握手和四 ...

随机推荐

  1. Codeforces Gym101170J:Jupiter Orbiter(最大流)

    题目链接 题意 有n次事件,q个队列,s个传感器.每个传感器接到一个队列,每个队列有一个容量. 接下来执行n次事件,每次事件都会有一个最大发送数据量d.和s个数据a,代表这次给每个s填入a的数据量. ...

  2. vue中修改子组件样式

    一.问题叙述 项目里需要新添加一个表单页面,里面就只是几个select,这个几个select是原本封装好的组件,有自己原本的样式,而这次的原型图却没有和之前的样式统一起来,需要微调一下,这里就涉及到父 ...

  3. C++学习书籍推荐《More Exceptional C++》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <More Exceptional C++:40个新的工程难题.编程疑问及解决方法(中文版)>作为广为人知的<Exceptional C++ ...

  4. Unity《ATD》塔防RPG类3D游戏架构设计(二)

    目录 <ATD> 游戏模型 <ATD> 游戏逻辑 <ATD> UI/HUD/特效/音乐 结语 前篇:Unity<ATD>塔防RPG类3D游戏架构设计(一 ...

  5. 理解vue-loader

    事情的起源是被人问到,一个以.vue结尾的文件,是如何被编译然后运行在浏览器中的?突然发现,对这一块模糊的很,而且看mpvue的文档,甚至小程序之类的都是实现了自己的loader,所以十分必要抽时间去 ...

  6. 从四个属性的角度来理解C语言的指针也许会更好理解

    文章会在文末更新! 关于指针是什么,很多教材已经作出了定义,大多数都会定义为"存放变量内存地址的变量".从这句话中我觉得除了让我知道这个定义有11个字以外,其他就没什么用了.我个人 ...

  7. 个人永久性免费-Excel催化剂功能第96波-地图数据挖宝之全国天气查询(区域最细可到区县,最长预报4天)

    天气预报的信息,是很普通的大家习以为常的信息,但如果不进行采集,在日常数据分析过程中,就少了非常重要的一个分析维度,如果人手采集整理,工作量巨大.此篇给广大数据分析工作者再次减负,只需简单一键,即可批 ...

  8. sklearn使用技巧

    sklearn使用技巧 sklearn上面对自己api的解释已经做的淋漓尽致,但对于只需要短时间入手的同学来说,还是比较复杂的,下面将会列举sklearn的使用技巧. 预处理 主要在sklearn.p ...

  9. 简单分析线程获取ReentrantReadWriteLock 读锁的规则

    1. 问题 最近有同事问了我一个问题,在Java编程中,当有一条线程要获取ReentrantReadWriteLock的读锁,此时已经有其他线程获得了读锁,AQS队列里也有线程在等待写锁.由于读锁是共 ...

  10. 前端响应式のmedia文件分离

    响应式cssのmedia文件分离 media简介 1.媒体查询,添加自CSS3 2.一个媒体查询由一个可选的媒体类型和零个或多个使用媒体功能的限制了样式表范围的表达式组成,允许内容的呈现针对一个特定范 ...