赞
踩
RPC是Remote Procedure Call的简称,中文叫远程过程调用。
说的白话一点,可以这么理解:现在有两台服务器A和B。部署在A服务器上的应用,想调用部署在B服务器上的另一个应用提供的方法,由于不在一个内存空间,不能直接调用,需要通过网络来达到调用的效果。
现在,我们在A服务的一个本地方法中封装调用B的逻辑,然后只需要在本地使用这个方法,就达到了调用B的效果。
对使用者来说,屏蔽了细节。你只需要知道调用这个方法返回的结果,而无需关注底层逻辑。
那,从封装的那个方法角度来看,调用B之前我们需要知道什么?
当然是一些约定啊。比如,
调用的语义,也可以理解为接口规范。(比如RESTful)
网络传输协议 (比如HTTP)
数据序列化反序列化规范(比如JSON)。
有了这些约定,我就知道如何给你发数据,发什么样的数据,你返回给我的又是什么样的数据。
从上图中可以看出,RPC是一种客户端-服务端(Client/Server)模式。
从某种角度来看,所有本身应用程序之外的调用都可以归类为RPC。无论是微服务、第三方HTTP接口,还是读写数据库中间件Mysql、Redis。
首先这个问题本身不太严谨。
HTTP只是一个通信协议,工作在OSI第七层。
而RPC是一个完整的远程调用方案。它包含了:接口规范、传输协议、数据序列化反序列化规范。
这样看,RPC和 HTTP的关系只可能是包含关系。为什么是可能?因为RPC传输协议那块我可以不基于HTTP呀。
所以这个问题应该改成:基于HTTP的远程调用方案 (如:HTTP+RESTful+JSON) 和直接使用RPC远程调用方案有什么区别?
gRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。
gRPC基于 HTTP/2协议传输。而HTTP/2相比HTTP1.x,有以下一些优势:
用于数据传输的二进制分帧
HTTP/2采用二进制格式传输协议,而非HTTP/1.x的文本格式。
多路复用
HTTP/2支持通过同一个连接发送多个并发的请求。
而HTTP/1.x虽然通过pipeline也能并发请求,但多个请求之间的响应依然会被阻塞。
服务端推送
服务端推送是一种在客户端请求之前发送数据的机制。在HTTP/2中,服务器可以对客户端的一个请求发送多个响应。而不像HTTP/1.X一样,只能通过客户端发起request,服务端才产生对应的response。
减少网络流量的头部压缩。
HTTP/2对消息头进行了压缩传输,能够节省消息头占用的网络流量。
官网有一张图:
从上图和文档中可以看出,用gRPC来进行远程调用服务,客户端(client) 仅仅需要gRPC Stub(为啥叫存根?) ,通过Proto Request向gRPC Server发起服务调用,然后 gRPC Server通过Proto Response(s)将调用结果返回给调用的client。
Protobuf是Protocol Buffers的简称,gRPC使用Protocol Buffers作为序列化协议。Protocol Buffers是Google公司开发的一种数据描述语言,用于描述一种轻便高效的结构化数据存储格式,它是一种与语言、平台无关 、可扩展的序列化结构数据。它的定位类似于JSON、XML,但是比他们更小、更快、更简单,于2008年对外开源。Protobuf可以用于结构化数据串行化,或者说序列化。它的设计非常适用于在网络通讯中的数据载体,很适合做数据存储或 RPC 数据交换格式,它序列化出来的数据量少再加上以 K-V 的方式来存储数据,对消息的版本兼容性非常强,可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。开发者可以通过Protobuf附带的工具生成代码并实现将结构化数据序列化的功能。
下面对照着一个.proto文件简单介绍下Protobuf的语法
syntax = "proto3";
enum OrderBy{
Order_Desc = 0;
Order_Asc = 1;
}
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
OrderBy order_by = 4;
}
.proto文件的第一行指定了使用 proto3语法。如果省略protocol buffer编译器默认使用 proto2语法。他必须是文件中非空非注释行的第一行。
SearchRequest定义中指定了三个字段(name/value键值对),每个字段都会有名称和类型。
上面的例子中,所有的字段都是标量类型的两个整型(pagenumber和resultper_page)和一个字符串型(query)。不过你还可以给字段指定复合类型,包括枚举类型和其他message类型
在message定义中每个字段都有一个唯一的编号,这些编号被用来在二进制消息体中识别你定义的这些字段,一旦你的message类型被用到后就不应该在修改这些编号了。注意在将message编码成二进制消息体时字段编号1-15将会占用1个字节,16-2047将占用两个字节。所以在一些频繁使用用的message中,你应该总是先使用前面1-15字段编号。
你可以指定的最小编号是1,最大是2E29 - 1(536,870,911)。其中19000到19999是给protocol buffers实现保留的字段标号,定义message时不能使用。同样的你也不能重复使用任何当前message定义里已经使用过和预留的字段编号。
message的字段必须符合以下规则:
singular:一个遵循singular规则的字段,在一个结构良好的message消息体(编码后的message)可以有0或1个该字段(但是不可以有多个)。这是proto3语法的默认字段规则。(这个理解起来有些晦涩,举例来说上面例子中四个字段都是singular类型的字段,在编码后的消息体中可以有0或者1个query字段,但不会有多个。)
repeated:遵循repeated规则的字段在消息体重可以有任意多个该字段值,这些值的顺序在消息体重可以保持(就是数组类型的字段)
在单个 .proto文件中可以定义多个message,这在定义多个相关message时非常有用。比如说,我们定义 SearchRequest对应的响应message SearchResponse ,把它加到之前的 .proto文件中。
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
OrderBy order_by = 4;
}
message SearchResponse { ...}
.proto文件中的注释和C,C++的注释风格相同,使用// 和 /* … */
当时一个被编码的message体中不存在某个message定义中的singular字段时,在message体解析成的对象中,相应字段会被设置为message定义中该字段的默认值。默认值依类型而定:
对于字符串,默认值为空字符串。
对于字节,默认值为空字节。
对于bools,默认值为false。
对于数字类型,默认值为零。
对于枚举,默认值是第一个定义的枚举值,该值必须为0。
对于消息字段,未设置该字段。它的确切值取决于语言。有关详细信息,请参阅代码生成指南。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。